1*e4b17023SJohn Marino /* Memory address lowering and addressing mode selection.
2*e4b17023SJohn Marino Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2011
3*e4b17023SJohn Marino Free Software Foundation, Inc.
4*e4b17023SJohn Marino
5*e4b17023SJohn Marino This file is part of GCC.
6*e4b17023SJohn Marino
7*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it
8*e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
9*e4b17023SJohn Marino Free Software Foundation; either version 3, or (at your option) any
10*e4b17023SJohn Marino later version.
11*e4b17023SJohn Marino
12*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
13*e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15*e4b17023SJohn Marino for more details.
16*e4b17023SJohn Marino
17*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18*e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
19*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
20*e4b17023SJohn Marino
21*e4b17023SJohn Marino /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
22*e4b17023SJohn Marino that directly map to addressing modes of the target. */
23*e4b17023SJohn Marino
24*e4b17023SJohn Marino #include "config.h"
25*e4b17023SJohn Marino #include "system.h"
26*e4b17023SJohn Marino #include "coretypes.h"
27*e4b17023SJohn Marino #include "tm.h"
28*e4b17023SJohn Marino #include "tree.h"
29*e4b17023SJohn Marino #include "tm_p.h"
30*e4b17023SJohn Marino #include "basic-block.h"
31*e4b17023SJohn Marino #include "output.h"
32*e4b17023SJohn Marino #include "tree-pretty-print.h"
33*e4b17023SJohn Marino #include "tree-flow.h"
34*e4b17023SJohn Marino #include "tree-dump.h"
35*e4b17023SJohn Marino #include "tree-pass.h"
36*e4b17023SJohn Marino #include "timevar.h"
37*e4b17023SJohn Marino #include "flags.h"
38*e4b17023SJohn Marino #include "tree-inline.h"
39*e4b17023SJohn Marino #include "tree-affine.h"
40*e4b17023SJohn Marino
41*e4b17023SJohn Marino /* FIXME: We compute address costs using RTL. */
42*e4b17023SJohn Marino #include "insn-config.h"
43*e4b17023SJohn Marino #include "rtl.h"
44*e4b17023SJohn Marino #include "recog.h"
45*e4b17023SJohn Marino #include "expr.h"
46*e4b17023SJohn Marino #include "ggc.h"
47*e4b17023SJohn Marino #include "target.h"
48*e4b17023SJohn Marino
49*e4b17023SJohn Marino /* TODO -- handling of symbols (according to Richard Hendersons
50*e4b17023SJohn Marino comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
51*e4b17023SJohn Marino
52*e4b17023SJohn Marino There are at least 5 different kinds of symbols that we can run up against:
53*e4b17023SJohn Marino
54*e4b17023SJohn Marino (1) binds_local_p, small data area.
55*e4b17023SJohn Marino (2) binds_local_p, eg local statics
56*e4b17023SJohn Marino (3) !binds_local_p, eg global variables
57*e4b17023SJohn Marino (4) thread local, local_exec
58*e4b17023SJohn Marino (5) thread local, !local_exec
59*e4b17023SJohn Marino
60*e4b17023SJohn Marino Now, (1) won't appear often in an array context, but it certainly can.
61*e4b17023SJohn Marino All you have to do is set -GN high enough, or explicitly mark any
62*e4b17023SJohn Marino random object __attribute__((section (".sdata"))).
63*e4b17023SJohn Marino
64*e4b17023SJohn Marino All of these affect whether or not a symbol is in fact a valid address.
65*e4b17023SJohn Marino The only one tested here is (3). And that result may very well
66*e4b17023SJohn Marino be incorrect for (4) or (5).
67*e4b17023SJohn Marino
68*e4b17023SJohn Marino An incorrect result here does not cause incorrect results out the
69*e4b17023SJohn Marino back end, because the expander in expr.c validizes the address. However
70*e4b17023SJohn Marino it would be nice to improve the handling here in order to produce more
71*e4b17023SJohn Marino precise results. */
72*e4b17023SJohn Marino
73*e4b17023SJohn Marino /* A "template" for memory address, used to determine whether the address is
74*e4b17023SJohn Marino valid for mode. */
75*e4b17023SJohn Marino
76*e4b17023SJohn Marino typedef struct GTY (()) mem_addr_template {
77*e4b17023SJohn Marino rtx ref; /* The template. */
78*e4b17023SJohn Marino rtx * GTY ((skip)) step_p; /* The point in template where the step should be
79*e4b17023SJohn Marino filled in. */
80*e4b17023SJohn Marino rtx * GTY ((skip)) off_p; /* The point in template where the offset should
81*e4b17023SJohn Marino be filled in. */
82*e4b17023SJohn Marino } mem_addr_template;
83*e4b17023SJohn Marino
84*e4b17023SJohn Marino DEF_VEC_O (mem_addr_template);
85*e4b17023SJohn Marino DEF_VEC_ALLOC_O (mem_addr_template, gc);
86*e4b17023SJohn Marino
87*e4b17023SJohn Marino /* The templates. Each of the low five bits of the index corresponds to one
88*e4b17023SJohn Marino component of TARGET_MEM_REF being present, while the high bits identify
89*e4b17023SJohn Marino the address space. See TEMPL_IDX. */
90*e4b17023SJohn Marino
91*e4b17023SJohn Marino static GTY(()) VEC (mem_addr_template, gc) *mem_addr_template_list;
92*e4b17023SJohn Marino
93*e4b17023SJohn Marino #define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
94*e4b17023SJohn Marino (((int) (AS) << 5) \
95*e4b17023SJohn Marino | ((SYMBOL != 0) << 4) \
96*e4b17023SJohn Marino | ((BASE != 0) << 3) \
97*e4b17023SJohn Marino | ((INDEX != 0) << 2) \
98*e4b17023SJohn Marino | ((STEP != 0) << 1) \
99*e4b17023SJohn Marino | (OFFSET != 0))
100*e4b17023SJohn Marino
101*e4b17023SJohn Marino /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
102*e4b17023SJohn Marino STEP and OFFSET to *ADDR using address mode ADDRESS_MODE. Stores pointers
103*e4b17023SJohn Marino to where step is placed to *STEP_P and offset to *OFFSET_P. */
104*e4b17023SJohn Marino
105*e4b17023SJohn Marino static void
gen_addr_rtx(enum machine_mode address_mode,rtx symbol,rtx base,rtx index,rtx step,rtx offset,rtx * addr,rtx ** step_p,rtx ** offset_p)106*e4b17023SJohn Marino gen_addr_rtx (enum machine_mode address_mode,
107*e4b17023SJohn Marino rtx symbol, rtx base, rtx index, rtx step, rtx offset,
108*e4b17023SJohn Marino rtx *addr, rtx **step_p, rtx **offset_p)
109*e4b17023SJohn Marino {
110*e4b17023SJohn Marino rtx act_elem;
111*e4b17023SJohn Marino
112*e4b17023SJohn Marino *addr = NULL_RTX;
113*e4b17023SJohn Marino if (step_p)
114*e4b17023SJohn Marino *step_p = NULL;
115*e4b17023SJohn Marino if (offset_p)
116*e4b17023SJohn Marino *offset_p = NULL;
117*e4b17023SJohn Marino
118*e4b17023SJohn Marino if (index)
119*e4b17023SJohn Marino {
120*e4b17023SJohn Marino act_elem = index;
121*e4b17023SJohn Marino if (step)
122*e4b17023SJohn Marino {
123*e4b17023SJohn Marino act_elem = gen_rtx_MULT (address_mode, act_elem, step);
124*e4b17023SJohn Marino
125*e4b17023SJohn Marino if (step_p)
126*e4b17023SJohn Marino *step_p = &XEXP (act_elem, 1);
127*e4b17023SJohn Marino }
128*e4b17023SJohn Marino
129*e4b17023SJohn Marino *addr = act_elem;
130*e4b17023SJohn Marino }
131*e4b17023SJohn Marino
132*e4b17023SJohn Marino if (base && base != const0_rtx)
133*e4b17023SJohn Marino {
134*e4b17023SJohn Marino if (*addr)
135*e4b17023SJohn Marino *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
136*e4b17023SJohn Marino else
137*e4b17023SJohn Marino *addr = base;
138*e4b17023SJohn Marino }
139*e4b17023SJohn Marino
140*e4b17023SJohn Marino if (symbol)
141*e4b17023SJohn Marino {
142*e4b17023SJohn Marino act_elem = symbol;
143*e4b17023SJohn Marino if (offset)
144*e4b17023SJohn Marino {
145*e4b17023SJohn Marino act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
146*e4b17023SJohn Marino
147*e4b17023SJohn Marino if (offset_p)
148*e4b17023SJohn Marino *offset_p = &XEXP (act_elem, 1);
149*e4b17023SJohn Marino
150*e4b17023SJohn Marino if (GET_CODE (symbol) == SYMBOL_REF
151*e4b17023SJohn Marino || GET_CODE (symbol) == LABEL_REF
152*e4b17023SJohn Marino || GET_CODE (symbol) == CONST)
153*e4b17023SJohn Marino act_elem = gen_rtx_CONST (address_mode, act_elem);
154*e4b17023SJohn Marino }
155*e4b17023SJohn Marino
156*e4b17023SJohn Marino if (*addr)
157*e4b17023SJohn Marino *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
158*e4b17023SJohn Marino else
159*e4b17023SJohn Marino *addr = act_elem;
160*e4b17023SJohn Marino }
161*e4b17023SJohn Marino else if (offset)
162*e4b17023SJohn Marino {
163*e4b17023SJohn Marino if (*addr)
164*e4b17023SJohn Marino {
165*e4b17023SJohn Marino *addr = gen_rtx_PLUS (address_mode, *addr, offset);
166*e4b17023SJohn Marino if (offset_p)
167*e4b17023SJohn Marino *offset_p = &XEXP (*addr, 1);
168*e4b17023SJohn Marino }
169*e4b17023SJohn Marino else
170*e4b17023SJohn Marino {
171*e4b17023SJohn Marino *addr = offset;
172*e4b17023SJohn Marino if (offset_p)
173*e4b17023SJohn Marino *offset_p = addr;
174*e4b17023SJohn Marino }
175*e4b17023SJohn Marino }
176*e4b17023SJohn Marino
177*e4b17023SJohn Marino if (!*addr)
178*e4b17023SJohn Marino *addr = const0_rtx;
179*e4b17023SJohn Marino }
180*e4b17023SJohn Marino
181*e4b17023SJohn Marino /* Returns address for TARGET_MEM_REF with parameters given by ADDR
182*e4b17023SJohn Marino in address space AS.
183*e4b17023SJohn Marino If REALLY_EXPAND is false, just make fake registers instead
184*e4b17023SJohn Marino of really expanding the operands, and perform the expansion in-place
185*e4b17023SJohn Marino by using one of the "templates". */
186*e4b17023SJohn Marino
187*e4b17023SJohn Marino rtx
addr_for_mem_ref(struct mem_address * addr,addr_space_t as,bool really_expand)188*e4b17023SJohn Marino addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
189*e4b17023SJohn Marino bool really_expand)
190*e4b17023SJohn Marino {
191*e4b17023SJohn Marino enum machine_mode address_mode = targetm.addr_space.address_mode (as);
192*e4b17023SJohn Marino enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
193*e4b17023SJohn Marino rtx address, sym, bse, idx, st, off;
194*e4b17023SJohn Marino struct mem_addr_template *templ;
195*e4b17023SJohn Marino
196*e4b17023SJohn Marino if (addr->step && !integer_onep (addr->step))
197*e4b17023SJohn Marino st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
198*e4b17023SJohn Marino else
199*e4b17023SJohn Marino st = NULL_RTX;
200*e4b17023SJohn Marino
201*e4b17023SJohn Marino if (addr->offset && !integer_zerop (addr->offset))
202*e4b17023SJohn Marino off = immed_double_int_const
203*e4b17023SJohn Marino (double_int_sext (tree_to_double_int (addr->offset),
204*e4b17023SJohn Marino TYPE_PRECISION (TREE_TYPE (addr->offset))),
205*e4b17023SJohn Marino pointer_mode);
206*e4b17023SJohn Marino else
207*e4b17023SJohn Marino off = NULL_RTX;
208*e4b17023SJohn Marino
209*e4b17023SJohn Marino if (!really_expand)
210*e4b17023SJohn Marino {
211*e4b17023SJohn Marino unsigned int templ_index
212*e4b17023SJohn Marino = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
213*e4b17023SJohn Marino
214*e4b17023SJohn Marino if (templ_index
215*e4b17023SJohn Marino >= VEC_length (mem_addr_template, mem_addr_template_list))
216*e4b17023SJohn Marino VEC_safe_grow_cleared (mem_addr_template, gc, mem_addr_template_list,
217*e4b17023SJohn Marino templ_index + 1);
218*e4b17023SJohn Marino
219*e4b17023SJohn Marino /* Reuse the templates for addresses, so that we do not waste memory. */
220*e4b17023SJohn Marino templ = VEC_index (mem_addr_template, mem_addr_template_list, templ_index);
221*e4b17023SJohn Marino if (!templ->ref)
222*e4b17023SJohn Marino {
223*e4b17023SJohn Marino sym = (addr->symbol ?
224*e4b17023SJohn Marino gen_rtx_SYMBOL_REF (pointer_mode, ggc_strdup ("test_symbol"))
225*e4b17023SJohn Marino : NULL_RTX);
226*e4b17023SJohn Marino bse = (addr->base ?
227*e4b17023SJohn Marino gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 1)
228*e4b17023SJohn Marino : NULL_RTX);
229*e4b17023SJohn Marino idx = (addr->index ?
230*e4b17023SJohn Marino gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 2)
231*e4b17023SJohn Marino : NULL_RTX);
232*e4b17023SJohn Marino
233*e4b17023SJohn Marino gen_addr_rtx (pointer_mode, sym, bse, idx,
234*e4b17023SJohn Marino st? const0_rtx : NULL_RTX,
235*e4b17023SJohn Marino off? const0_rtx : NULL_RTX,
236*e4b17023SJohn Marino &templ->ref,
237*e4b17023SJohn Marino &templ->step_p,
238*e4b17023SJohn Marino &templ->off_p);
239*e4b17023SJohn Marino }
240*e4b17023SJohn Marino
241*e4b17023SJohn Marino if (st)
242*e4b17023SJohn Marino *templ->step_p = st;
243*e4b17023SJohn Marino if (off)
244*e4b17023SJohn Marino *templ->off_p = off;
245*e4b17023SJohn Marino
246*e4b17023SJohn Marino return templ->ref;
247*e4b17023SJohn Marino }
248*e4b17023SJohn Marino
249*e4b17023SJohn Marino /* Otherwise really expand the expressions. */
250*e4b17023SJohn Marino sym = (addr->symbol
251*e4b17023SJohn Marino ? expand_expr (addr->symbol, NULL_RTX, pointer_mode, EXPAND_NORMAL)
252*e4b17023SJohn Marino : NULL_RTX);
253*e4b17023SJohn Marino bse = (addr->base
254*e4b17023SJohn Marino ? expand_expr (addr->base, NULL_RTX, pointer_mode, EXPAND_NORMAL)
255*e4b17023SJohn Marino : NULL_RTX);
256*e4b17023SJohn Marino idx = (addr->index
257*e4b17023SJohn Marino ? expand_expr (addr->index, NULL_RTX, pointer_mode, EXPAND_NORMAL)
258*e4b17023SJohn Marino : NULL_RTX);
259*e4b17023SJohn Marino
260*e4b17023SJohn Marino gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
261*e4b17023SJohn Marino if (pointer_mode != address_mode)
262*e4b17023SJohn Marino address = convert_memory_address (address_mode, address);
263*e4b17023SJohn Marino return address;
264*e4b17023SJohn Marino }
265*e4b17023SJohn Marino
266*e4b17023SJohn Marino /* Returns address of MEM_REF in TYPE. */
267*e4b17023SJohn Marino
268*e4b17023SJohn Marino tree
tree_mem_ref_addr(tree type,tree mem_ref)269*e4b17023SJohn Marino tree_mem_ref_addr (tree type, tree mem_ref)
270*e4b17023SJohn Marino {
271*e4b17023SJohn Marino tree addr;
272*e4b17023SJohn Marino tree act_elem;
273*e4b17023SJohn Marino tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
274*e4b17023SJohn Marino tree addr_base = NULL_TREE, addr_off = NULL_TREE;
275*e4b17023SJohn Marino
276*e4b17023SJohn Marino addr_base = fold_convert (type, TMR_BASE (mem_ref));
277*e4b17023SJohn Marino
278*e4b17023SJohn Marino act_elem = TMR_INDEX (mem_ref);
279*e4b17023SJohn Marino if (act_elem)
280*e4b17023SJohn Marino {
281*e4b17023SJohn Marino if (step)
282*e4b17023SJohn Marino act_elem = fold_build2 (MULT_EXPR, TREE_TYPE (act_elem),
283*e4b17023SJohn Marino act_elem, step);
284*e4b17023SJohn Marino addr_off = act_elem;
285*e4b17023SJohn Marino }
286*e4b17023SJohn Marino
287*e4b17023SJohn Marino act_elem = TMR_INDEX2 (mem_ref);
288*e4b17023SJohn Marino if (act_elem)
289*e4b17023SJohn Marino {
290*e4b17023SJohn Marino if (addr_off)
291*e4b17023SJohn Marino addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off),
292*e4b17023SJohn Marino addr_off, act_elem);
293*e4b17023SJohn Marino else
294*e4b17023SJohn Marino addr_off = act_elem;
295*e4b17023SJohn Marino }
296*e4b17023SJohn Marino
297*e4b17023SJohn Marino if (offset && !integer_zerop (offset))
298*e4b17023SJohn Marino {
299*e4b17023SJohn Marino if (addr_off)
300*e4b17023SJohn Marino addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off), addr_off,
301*e4b17023SJohn Marino fold_convert (TREE_TYPE (addr_off), offset));
302*e4b17023SJohn Marino else
303*e4b17023SJohn Marino addr_off = offset;
304*e4b17023SJohn Marino }
305*e4b17023SJohn Marino
306*e4b17023SJohn Marino if (addr_off)
307*e4b17023SJohn Marino addr = fold_build_pointer_plus (addr_base, addr_off);
308*e4b17023SJohn Marino else
309*e4b17023SJohn Marino addr = addr_base;
310*e4b17023SJohn Marino
311*e4b17023SJohn Marino return addr;
312*e4b17023SJohn Marino }
313*e4b17023SJohn Marino
314*e4b17023SJohn Marino /* Returns true if a memory reference in MODE and with parameters given by
315*e4b17023SJohn Marino ADDR is valid on the current target. */
316*e4b17023SJohn Marino
317*e4b17023SJohn Marino static bool
valid_mem_ref_p(enum machine_mode mode,addr_space_t as,struct mem_address * addr)318*e4b17023SJohn Marino valid_mem_ref_p (enum machine_mode mode, addr_space_t as,
319*e4b17023SJohn Marino struct mem_address *addr)
320*e4b17023SJohn Marino {
321*e4b17023SJohn Marino rtx address;
322*e4b17023SJohn Marino
323*e4b17023SJohn Marino address = addr_for_mem_ref (addr, as, false);
324*e4b17023SJohn Marino if (!address)
325*e4b17023SJohn Marino return false;
326*e4b17023SJohn Marino
327*e4b17023SJohn Marino return memory_address_addr_space_p (mode, address, as);
328*e4b17023SJohn Marino }
329*e4b17023SJohn Marino
330*e4b17023SJohn Marino /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
331*e4b17023SJohn Marino is valid on the current target and if so, creates and returns the
332*e4b17023SJohn Marino TARGET_MEM_REF. If VERIFY is false omit the verification step. */
333*e4b17023SJohn Marino
334*e4b17023SJohn Marino static tree
create_mem_ref_raw(tree type,tree alias_ptr_type,struct mem_address * addr,bool verify)335*e4b17023SJohn Marino create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr,
336*e4b17023SJohn Marino bool verify)
337*e4b17023SJohn Marino {
338*e4b17023SJohn Marino tree base, index2;
339*e4b17023SJohn Marino
340*e4b17023SJohn Marino if (verify
341*e4b17023SJohn Marino && !valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
342*e4b17023SJohn Marino return NULL_TREE;
343*e4b17023SJohn Marino
344*e4b17023SJohn Marino if (addr->step && integer_onep (addr->step))
345*e4b17023SJohn Marino addr->step = NULL_TREE;
346*e4b17023SJohn Marino
347*e4b17023SJohn Marino if (addr->offset)
348*e4b17023SJohn Marino addr->offset = fold_convert (alias_ptr_type, addr->offset);
349*e4b17023SJohn Marino else
350*e4b17023SJohn Marino addr->offset = build_int_cst (alias_ptr_type, 0);
351*e4b17023SJohn Marino
352*e4b17023SJohn Marino if (addr->symbol)
353*e4b17023SJohn Marino {
354*e4b17023SJohn Marino base = addr->symbol;
355*e4b17023SJohn Marino index2 = addr->base;
356*e4b17023SJohn Marino }
357*e4b17023SJohn Marino else if (addr->base
358*e4b17023SJohn Marino && POINTER_TYPE_P (TREE_TYPE (addr->base)))
359*e4b17023SJohn Marino {
360*e4b17023SJohn Marino base = addr->base;
361*e4b17023SJohn Marino index2 = NULL_TREE;
362*e4b17023SJohn Marino }
363*e4b17023SJohn Marino else
364*e4b17023SJohn Marino {
365*e4b17023SJohn Marino base = build_int_cst (ptr_type_node, 0);
366*e4b17023SJohn Marino index2 = addr->base;
367*e4b17023SJohn Marino }
368*e4b17023SJohn Marino
369*e4b17023SJohn Marino /* If possible use a plain MEM_REF instead of a TARGET_MEM_REF.
370*e4b17023SJohn Marino ??? As IVOPTs does not follow restrictions to where the base
371*e4b17023SJohn Marino pointer may point to create a MEM_REF only if we know that
372*e4b17023SJohn Marino base is valid. */
373*e4b17023SJohn Marino if ((TREE_CODE (base) == ADDR_EXPR || TREE_CODE (base) == INTEGER_CST)
374*e4b17023SJohn Marino && (!index2 || integer_zerop (index2))
375*e4b17023SJohn Marino && (!addr->index || integer_zerop (addr->index)))
376*e4b17023SJohn Marino return fold_build2 (MEM_REF, type, base, addr->offset);
377*e4b17023SJohn Marino
378*e4b17023SJohn Marino return build5 (TARGET_MEM_REF, type,
379*e4b17023SJohn Marino base, addr->offset, addr->index, addr->step, index2);
380*e4b17023SJohn Marino }
381*e4b17023SJohn Marino
382*e4b17023SJohn Marino /* Returns true if OBJ is an object whose address is a link time constant. */
383*e4b17023SJohn Marino
384*e4b17023SJohn Marino static bool
fixed_address_object_p(tree obj)385*e4b17023SJohn Marino fixed_address_object_p (tree obj)
386*e4b17023SJohn Marino {
387*e4b17023SJohn Marino return (TREE_CODE (obj) == VAR_DECL
388*e4b17023SJohn Marino && (TREE_STATIC (obj)
389*e4b17023SJohn Marino || DECL_EXTERNAL (obj))
390*e4b17023SJohn Marino && ! DECL_DLLIMPORT_P (obj));
391*e4b17023SJohn Marino }
392*e4b17023SJohn Marino
393*e4b17023SJohn Marino /* If ADDR contains an address of object that is a link time constant,
394*e4b17023SJohn Marino move it to PARTS->symbol. */
395*e4b17023SJohn Marino
396*e4b17023SJohn Marino static void
move_fixed_address_to_symbol(struct mem_address * parts,aff_tree * addr)397*e4b17023SJohn Marino move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
398*e4b17023SJohn Marino {
399*e4b17023SJohn Marino unsigned i;
400*e4b17023SJohn Marino tree val = NULL_TREE;
401*e4b17023SJohn Marino
402*e4b17023SJohn Marino for (i = 0; i < addr->n; i++)
403*e4b17023SJohn Marino {
404*e4b17023SJohn Marino if (!double_int_one_p (addr->elts[i].coef))
405*e4b17023SJohn Marino continue;
406*e4b17023SJohn Marino
407*e4b17023SJohn Marino val = addr->elts[i].val;
408*e4b17023SJohn Marino if (TREE_CODE (val) == ADDR_EXPR
409*e4b17023SJohn Marino && fixed_address_object_p (TREE_OPERAND (val, 0)))
410*e4b17023SJohn Marino break;
411*e4b17023SJohn Marino }
412*e4b17023SJohn Marino
413*e4b17023SJohn Marino if (i == addr->n)
414*e4b17023SJohn Marino return;
415*e4b17023SJohn Marino
416*e4b17023SJohn Marino parts->symbol = val;
417*e4b17023SJohn Marino aff_combination_remove_elt (addr, i);
418*e4b17023SJohn Marino }
419*e4b17023SJohn Marino
420*e4b17023SJohn Marino /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base. */
421*e4b17023SJohn Marino
422*e4b17023SJohn Marino static void
move_hint_to_base(tree type,struct mem_address * parts,tree base_hint,aff_tree * addr)423*e4b17023SJohn Marino move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
424*e4b17023SJohn Marino aff_tree *addr)
425*e4b17023SJohn Marino {
426*e4b17023SJohn Marino unsigned i;
427*e4b17023SJohn Marino tree val = NULL_TREE;
428*e4b17023SJohn Marino int qual;
429*e4b17023SJohn Marino
430*e4b17023SJohn Marino for (i = 0; i < addr->n; i++)
431*e4b17023SJohn Marino {
432*e4b17023SJohn Marino if (!double_int_one_p (addr->elts[i].coef))
433*e4b17023SJohn Marino continue;
434*e4b17023SJohn Marino
435*e4b17023SJohn Marino val = addr->elts[i].val;
436*e4b17023SJohn Marino if (operand_equal_p (val, base_hint, 0))
437*e4b17023SJohn Marino break;
438*e4b17023SJohn Marino }
439*e4b17023SJohn Marino
440*e4b17023SJohn Marino if (i == addr->n)
441*e4b17023SJohn Marino return;
442*e4b17023SJohn Marino
443*e4b17023SJohn Marino /* Cast value to appropriate pointer type. We cannot use a pointer
444*e4b17023SJohn Marino to TYPE directly, as the back-end will assume registers of pointer
445*e4b17023SJohn Marino type are aligned, and just the base itself may not actually be.
446*e4b17023SJohn Marino We use void pointer to the type's address space instead. */
447*e4b17023SJohn Marino qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
448*e4b17023SJohn Marino type = build_qualified_type (void_type_node, qual);
449*e4b17023SJohn Marino parts->base = fold_convert (build_pointer_type (type), val);
450*e4b17023SJohn Marino aff_combination_remove_elt (addr, i);
451*e4b17023SJohn Marino }
452*e4b17023SJohn Marino
453*e4b17023SJohn Marino /* If ADDR contains an address of a dereferenced pointer, move it to
454*e4b17023SJohn Marino PARTS->base. */
455*e4b17023SJohn Marino
456*e4b17023SJohn Marino static void
move_pointer_to_base(struct mem_address * parts,aff_tree * addr)457*e4b17023SJohn Marino move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
458*e4b17023SJohn Marino {
459*e4b17023SJohn Marino unsigned i;
460*e4b17023SJohn Marino tree val = NULL_TREE;
461*e4b17023SJohn Marino
462*e4b17023SJohn Marino for (i = 0; i < addr->n; i++)
463*e4b17023SJohn Marino {
464*e4b17023SJohn Marino if (!double_int_one_p (addr->elts[i].coef))
465*e4b17023SJohn Marino continue;
466*e4b17023SJohn Marino
467*e4b17023SJohn Marino val = addr->elts[i].val;
468*e4b17023SJohn Marino if (POINTER_TYPE_P (TREE_TYPE (val)))
469*e4b17023SJohn Marino break;
470*e4b17023SJohn Marino }
471*e4b17023SJohn Marino
472*e4b17023SJohn Marino if (i == addr->n)
473*e4b17023SJohn Marino return;
474*e4b17023SJohn Marino
475*e4b17023SJohn Marino parts->base = val;
476*e4b17023SJohn Marino aff_combination_remove_elt (addr, i);
477*e4b17023SJohn Marino }
478*e4b17023SJohn Marino
479*e4b17023SJohn Marino /* Moves the loop variant part V in linear address ADDR to be the index
480*e4b17023SJohn Marino of PARTS. */
481*e4b17023SJohn Marino
482*e4b17023SJohn Marino static void
move_variant_to_index(struct mem_address * parts,aff_tree * addr,tree v)483*e4b17023SJohn Marino move_variant_to_index (struct mem_address *parts, aff_tree *addr, tree v)
484*e4b17023SJohn Marino {
485*e4b17023SJohn Marino unsigned i;
486*e4b17023SJohn Marino tree val = NULL_TREE;
487*e4b17023SJohn Marino
488*e4b17023SJohn Marino gcc_assert (!parts->index);
489*e4b17023SJohn Marino for (i = 0; i < addr->n; i++)
490*e4b17023SJohn Marino {
491*e4b17023SJohn Marino val = addr->elts[i].val;
492*e4b17023SJohn Marino if (operand_equal_p (val, v, 0))
493*e4b17023SJohn Marino break;
494*e4b17023SJohn Marino }
495*e4b17023SJohn Marino
496*e4b17023SJohn Marino if (i == addr->n)
497*e4b17023SJohn Marino return;
498*e4b17023SJohn Marino
499*e4b17023SJohn Marino parts->index = fold_convert (sizetype, val);
500*e4b17023SJohn Marino parts->step = double_int_to_tree (sizetype, addr->elts[i].coef);
501*e4b17023SJohn Marino aff_combination_remove_elt (addr, i);
502*e4b17023SJohn Marino }
503*e4b17023SJohn Marino
504*e4b17023SJohn Marino /* Adds ELT to PARTS. */
505*e4b17023SJohn Marino
506*e4b17023SJohn Marino static void
add_to_parts(struct mem_address * parts,tree elt)507*e4b17023SJohn Marino add_to_parts (struct mem_address *parts, tree elt)
508*e4b17023SJohn Marino {
509*e4b17023SJohn Marino tree type;
510*e4b17023SJohn Marino
511*e4b17023SJohn Marino if (!parts->index)
512*e4b17023SJohn Marino {
513*e4b17023SJohn Marino parts->index = fold_convert (sizetype, elt);
514*e4b17023SJohn Marino return;
515*e4b17023SJohn Marino }
516*e4b17023SJohn Marino
517*e4b17023SJohn Marino if (!parts->base)
518*e4b17023SJohn Marino {
519*e4b17023SJohn Marino parts->base = elt;
520*e4b17023SJohn Marino return;
521*e4b17023SJohn Marino }
522*e4b17023SJohn Marino
523*e4b17023SJohn Marino /* Add ELT to base. */
524*e4b17023SJohn Marino type = TREE_TYPE (parts->base);
525*e4b17023SJohn Marino if (POINTER_TYPE_P (type))
526*e4b17023SJohn Marino parts->base = fold_build_pointer_plus (parts->base, elt);
527*e4b17023SJohn Marino else
528*e4b17023SJohn Marino parts->base = fold_build2 (PLUS_EXPR, type,
529*e4b17023SJohn Marino parts->base, elt);
530*e4b17023SJohn Marino }
531*e4b17023SJohn Marino
532*e4b17023SJohn Marino /* Finds the most expensive multiplication in ADDR that can be
533*e4b17023SJohn Marino expressed in an addressing mode and move the corresponding
534*e4b17023SJohn Marino element(s) to PARTS. */
535*e4b17023SJohn Marino
536*e4b17023SJohn Marino static void
most_expensive_mult_to_index(tree type,struct mem_address * parts,aff_tree * addr,bool speed)537*e4b17023SJohn Marino most_expensive_mult_to_index (tree type, struct mem_address *parts,
538*e4b17023SJohn Marino aff_tree *addr, bool speed)
539*e4b17023SJohn Marino {
540*e4b17023SJohn Marino addr_space_t as = TYPE_ADDR_SPACE (type);
541*e4b17023SJohn Marino enum machine_mode address_mode = targetm.addr_space.address_mode (as);
542*e4b17023SJohn Marino HOST_WIDE_INT coef;
543*e4b17023SJohn Marino double_int best_mult, amult, amult_neg;
544*e4b17023SJohn Marino unsigned best_mult_cost = 0, acost;
545*e4b17023SJohn Marino tree mult_elt = NULL_TREE, elt;
546*e4b17023SJohn Marino unsigned i, j;
547*e4b17023SJohn Marino enum tree_code op_code;
548*e4b17023SJohn Marino
549*e4b17023SJohn Marino best_mult = double_int_zero;
550*e4b17023SJohn Marino for (i = 0; i < addr->n; i++)
551*e4b17023SJohn Marino {
552*e4b17023SJohn Marino if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
553*e4b17023SJohn Marino continue;
554*e4b17023SJohn Marino
555*e4b17023SJohn Marino coef = double_int_to_shwi (addr->elts[i].coef);
556*e4b17023SJohn Marino if (coef == 1
557*e4b17023SJohn Marino || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
558*e4b17023SJohn Marino continue;
559*e4b17023SJohn Marino
560*e4b17023SJohn Marino acost = multiply_by_cost (coef, address_mode, speed);
561*e4b17023SJohn Marino
562*e4b17023SJohn Marino if (acost > best_mult_cost)
563*e4b17023SJohn Marino {
564*e4b17023SJohn Marino best_mult_cost = acost;
565*e4b17023SJohn Marino best_mult = addr->elts[i].coef;
566*e4b17023SJohn Marino }
567*e4b17023SJohn Marino }
568*e4b17023SJohn Marino
569*e4b17023SJohn Marino if (!best_mult_cost)
570*e4b17023SJohn Marino return;
571*e4b17023SJohn Marino
572*e4b17023SJohn Marino /* Collect elements multiplied by best_mult. */
573*e4b17023SJohn Marino for (i = j = 0; i < addr->n; i++)
574*e4b17023SJohn Marino {
575*e4b17023SJohn Marino amult = addr->elts[i].coef;
576*e4b17023SJohn Marino amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
577*e4b17023SJohn Marino
578*e4b17023SJohn Marino if (double_int_equal_p (amult, best_mult))
579*e4b17023SJohn Marino op_code = PLUS_EXPR;
580*e4b17023SJohn Marino else if (double_int_equal_p (amult_neg, best_mult))
581*e4b17023SJohn Marino op_code = MINUS_EXPR;
582*e4b17023SJohn Marino else
583*e4b17023SJohn Marino {
584*e4b17023SJohn Marino addr->elts[j] = addr->elts[i];
585*e4b17023SJohn Marino j++;
586*e4b17023SJohn Marino continue;
587*e4b17023SJohn Marino }
588*e4b17023SJohn Marino
589*e4b17023SJohn Marino elt = fold_convert (sizetype, addr->elts[i].val);
590*e4b17023SJohn Marino if (mult_elt)
591*e4b17023SJohn Marino mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
592*e4b17023SJohn Marino else if (op_code == PLUS_EXPR)
593*e4b17023SJohn Marino mult_elt = elt;
594*e4b17023SJohn Marino else
595*e4b17023SJohn Marino mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
596*e4b17023SJohn Marino }
597*e4b17023SJohn Marino addr->n = j;
598*e4b17023SJohn Marino
599*e4b17023SJohn Marino parts->index = mult_elt;
600*e4b17023SJohn Marino parts->step = double_int_to_tree (sizetype, best_mult);
601*e4b17023SJohn Marino }
602*e4b17023SJohn Marino
603*e4b17023SJohn Marino /* Splits address ADDR for a memory access of type TYPE into PARTS.
604*e4b17023SJohn Marino If BASE_HINT is non-NULL, it specifies an SSA name to be used
605*e4b17023SJohn Marino preferentially as base of the reference, and IV_CAND is the selected
606*e4b17023SJohn Marino iv candidate used in ADDR.
607*e4b17023SJohn Marino
608*e4b17023SJohn Marino TODO -- be more clever about the distribution of the elements of ADDR
609*e4b17023SJohn Marino to PARTS. Some architectures do not support anything but single
610*e4b17023SJohn Marino register in address, possibly with a small integer offset; while
611*e4b17023SJohn Marino create_mem_ref will simplify the address to an acceptable shape
612*e4b17023SJohn Marino later, it would be more efficient to know that asking for complicated
613*e4b17023SJohn Marino addressing modes is useless. */
614*e4b17023SJohn Marino
615*e4b17023SJohn Marino static void
addr_to_parts(tree type,aff_tree * addr,tree iv_cand,tree base_hint,struct mem_address * parts,bool speed)616*e4b17023SJohn Marino addr_to_parts (tree type, aff_tree *addr, tree iv_cand,
617*e4b17023SJohn Marino tree base_hint, struct mem_address *parts,
618*e4b17023SJohn Marino bool speed)
619*e4b17023SJohn Marino {
620*e4b17023SJohn Marino tree part;
621*e4b17023SJohn Marino unsigned i;
622*e4b17023SJohn Marino
623*e4b17023SJohn Marino parts->symbol = NULL_TREE;
624*e4b17023SJohn Marino parts->base = NULL_TREE;
625*e4b17023SJohn Marino parts->index = NULL_TREE;
626*e4b17023SJohn Marino parts->step = NULL_TREE;
627*e4b17023SJohn Marino
628*e4b17023SJohn Marino if (!double_int_zero_p (addr->offset))
629*e4b17023SJohn Marino parts->offset = double_int_to_tree (sizetype, addr->offset);
630*e4b17023SJohn Marino else
631*e4b17023SJohn Marino parts->offset = NULL_TREE;
632*e4b17023SJohn Marino
633*e4b17023SJohn Marino /* Try to find a symbol. */
634*e4b17023SJohn Marino move_fixed_address_to_symbol (parts, addr);
635*e4b17023SJohn Marino
636*e4b17023SJohn Marino /* No need to do address parts reassociation if the number of parts
637*e4b17023SJohn Marino is <= 2 -- in that case, no loop invariant code motion can be
638*e4b17023SJohn Marino exposed. */
639*e4b17023SJohn Marino
640*e4b17023SJohn Marino if (!base_hint && (addr->n > 2))
641*e4b17023SJohn Marino move_variant_to_index (parts, addr, iv_cand);
642*e4b17023SJohn Marino
643*e4b17023SJohn Marino /* First move the most expensive feasible multiplication
644*e4b17023SJohn Marino to index. */
645*e4b17023SJohn Marino if (!parts->index)
646*e4b17023SJohn Marino most_expensive_mult_to_index (type, parts, addr, speed);
647*e4b17023SJohn Marino
648*e4b17023SJohn Marino /* Try to find a base of the reference. Since at the moment
649*e4b17023SJohn Marino there is no reliable way how to distinguish between pointer and its
650*e4b17023SJohn Marino offset, this is just a guess. */
651*e4b17023SJohn Marino if (!parts->symbol && base_hint)
652*e4b17023SJohn Marino move_hint_to_base (type, parts, base_hint, addr);
653*e4b17023SJohn Marino if (!parts->symbol && !parts->base)
654*e4b17023SJohn Marino move_pointer_to_base (parts, addr);
655*e4b17023SJohn Marino
656*e4b17023SJohn Marino /* Then try to process the remaining elements. */
657*e4b17023SJohn Marino for (i = 0; i < addr->n; i++)
658*e4b17023SJohn Marino {
659*e4b17023SJohn Marino part = fold_convert (sizetype, addr->elts[i].val);
660*e4b17023SJohn Marino if (!double_int_one_p (addr->elts[i].coef))
661*e4b17023SJohn Marino part = fold_build2 (MULT_EXPR, sizetype, part,
662*e4b17023SJohn Marino double_int_to_tree (sizetype, addr->elts[i].coef));
663*e4b17023SJohn Marino add_to_parts (parts, part);
664*e4b17023SJohn Marino }
665*e4b17023SJohn Marino if (addr->rest)
666*e4b17023SJohn Marino add_to_parts (parts, fold_convert (sizetype, addr->rest));
667*e4b17023SJohn Marino }
668*e4b17023SJohn Marino
669*e4b17023SJohn Marino /* Force the PARTS to register. */
670*e4b17023SJohn Marino
671*e4b17023SJohn Marino static void
gimplify_mem_ref_parts(gimple_stmt_iterator * gsi,struct mem_address * parts)672*e4b17023SJohn Marino gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
673*e4b17023SJohn Marino {
674*e4b17023SJohn Marino if (parts->base)
675*e4b17023SJohn Marino parts->base = force_gimple_operand_gsi_1 (gsi, parts->base,
676*e4b17023SJohn Marino is_gimple_mem_ref_addr, NULL_TREE,
677*e4b17023SJohn Marino true, GSI_SAME_STMT);
678*e4b17023SJohn Marino if (parts->index)
679*e4b17023SJohn Marino parts->index = force_gimple_operand_gsi (gsi, parts->index,
680*e4b17023SJohn Marino true, NULL_TREE,
681*e4b17023SJohn Marino true, GSI_SAME_STMT);
682*e4b17023SJohn Marino }
683*e4b17023SJohn Marino
684*e4b17023SJohn Marino /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
685*e4b17023SJohn Marino computations are emitted in front of GSI. TYPE is the mode
686*e4b17023SJohn Marino of created memory reference. IV_CAND is the selected iv candidate in ADDR,
687*e4b17023SJohn Marino and BASE_HINT is non NULL if IV_CAND comes from a base address
688*e4b17023SJohn Marino object. */
689*e4b17023SJohn Marino
690*e4b17023SJohn Marino tree
create_mem_ref(gimple_stmt_iterator * gsi,tree type,aff_tree * addr,tree alias_ptr_type,tree iv_cand,tree base_hint,bool speed)691*e4b17023SJohn Marino create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
692*e4b17023SJohn Marino tree alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
693*e4b17023SJohn Marino {
694*e4b17023SJohn Marino tree mem_ref, tmp;
695*e4b17023SJohn Marino struct mem_address parts;
696*e4b17023SJohn Marino
697*e4b17023SJohn Marino addr_to_parts (type, addr, iv_cand, base_hint, &parts, speed);
698*e4b17023SJohn Marino gimplify_mem_ref_parts (gsi, &parts);
699*e4b17023SJohn Marino mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
700*e4b17023SJohn Marino if (mem_ref)
701*e4b17023SJohn Marino return mem_ref;
702*e4b17023SJohn Marino
703*e4b17023SJohn Marino /* The expression is too complicated. Try making it simpler. */
704*e4b17023SJohn Marino
705*e4b17023SJohn Marino if (parts.step && !integer_onep (parts.step))
706*e4b17023SJohn Marino {
707*e4b17023SJohn Marino /* Move the multiplication to index. */
708*e4b17023SJohn Marino gcc_assert (parts.index);
709*e4b17023SJohn Marino parts.index = force_gimple_operand_gsi (gsi,
710*e4b17023SJohn Marino fold_build2 (MULT_EXPR, sizetype,
711*e4b17023SJohn Marino parts.index, parts.step),
712*e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
713*e4b17023SJohn Marino parts.step = NULL_TREE;
714*e4b17023SJohn Marino
715*e4b17023SJohn Marino mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
716*e4b17023SJohn Marino if (mem_ref)
717*e4b17023SJohn Marino return mem_ref;
718*e4b17023SJohn Marino }
719*e4b17023SJohn Marino
720*e4b17023SJohn Marino if (parts.symbol)
721*e4b17023SJohn Marino {
722*e4b17023SJohn Marino tmp = parts.symbol;
723*e4b17023SJohn Marino gcc_assert (is_gimple_val (tmp));
724*e4b17023SJohn Marino
725*e4b17023SJohn Marino /* Add the symbol to base, eventually forcing it to register. */
726*e4b17023SJohn Marino if (parts.base)
727*e4b17023SJohn Marino {
728*e4b17023SJohn Marino gcc_assert (useless_type_conversion_p
729*e4b17023SJohn Marino (sizetype, TREE_TYPE (parts.base)));
730*e4b17023SJohn Marino
731*e4b17023SJohn Marino if (parts.index)
732*e4b17023SJohn Marino {
733*e4b17023SJohn Marino parts.base = force_gimple_operand_gsi_1 (gsi,
734*e4b17023SJohn Marino fold_build_pointer_plus (tmp, parts.base),
735*e4b17023SJohn Marino is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
736*e4b17023SJohn Marino }
737*e4b17023SJohn Marino else
738*e4b17023SJohn Marino {
739*e4b17023SJohn Marino parts.index = parts.base;
740*e4b17023SJohn Marino parts.base = tmp;
741*e4b17023SJohn Marino }
742*e4b17023SJohn Marino }
743*e4b17023SJohn Marino else
744*e4b17023SJohn Marino parts.base = tmp;
745*e4b17023SJohn Marino parts.symbol = NULL_TREE;
746*e4b17023SJohn Marino
747*e4b17023SJohn Marino mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
748*e4b17023SJohn Marino if (mem_ref)
749*e4b17023SJohn Marino return mem_ref;
750*e4b17023SJohn Marino }
751*e4b17023SJohn Marino
752*e4b17023SJohn Marino if (parts.index)
753*e4b17023SJohn Marino {
754*e4b17023SJohn Marino /* Add index to base. */
755*e4b17023SJohn Marino if (parts.base)
756*e4b17023SJohn Marino {
757*e4b17023SJohn Marino parts.base = force_gimple_operand_gsi_1 (gsi,
758*e4b17023SJohn Marino fold_build_pointer_plus (parts.base, parts.index),
759*e4b17023SJohn Marino is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
760*e4b17023SJohn Marino }
761*e4b17023SJohn Marino else
762*e4b17023SJohn Marino parts.base = parts.index;
763*e4b17023SJohn Marino parts.index = NULL_TREE;
764*e4b17023SJohn Marino
765*e4b17023SJohn Marino mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
766*e4b17023SJohn Marino if (mem_ref)
767*e4b17023SJohn Marino return mem_ref;
768*e4b17023SJohn Marino }
769*e4b17023SJohn Marino
770*e4b17023SJohn Marino if (parts.offset && !integer_zerop (parts.offset))
771*e4b17023SJohn Marino {
772*e4b17023SJohn Marino /* Try adding offset to base. */
773*e4b17023SJohn Marino if (parts.base)
774*e4b17023SJohn Marino {
775*e4b17023SJohn Marino parts.base = force_gimple_operand_gsi_1 (gsi,
776*e4b17023SJohn Marino fold_build_pointer_plus (parts.base, parts.offset),
777*e4b17023SJohn Marino is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
778*e4b17023SJohn Marino }
779*e4b17023SJohn Marino else
780*e4b17023SJohn Marino parts.base = parts.offset;
781*e4b17023SJohn Marino
782*e4b17023SJohn Marino parts.offset = NULL_TREE;
783*e4b17023SJohn Marino
784*e4b17023SJohn Marino mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
785*e4b17023SJohn Marino if (mem_ref)
786*e4b17023SJohn Marino return mem_ref;
787*e4b17023SJohn Marino }
788*e4b17023SJohn Marino
789*e4b17023SJohn Marino /* Verify that the address is in the simplest possible shape
790*e4b17023SJohn Marino (only a register). If we cannot create such a memory reference,
791*e4b17023SJohn Marino something is really wrong. */
792*e4b17023SJohn Marino gcc_assert (parts.symbol == NULL_TREE);
793*e4b17023SJohn Marino gcc_assert (parts.index == NULL_TREE);
794*e4b17023SJohn Marino gcc_assert (!parts.step || integer_onep (parts.step));
795*e4b17023SJohn Marino gcc_assert (!parts.offset || integer_zerop (parts.offset));
796*e4b17023SJohn Marino gcc_unreachable ();
797*e4b17023SJohn Marino }
798*e4b17023SJohn Marino
799*e4b17023SJohn Marino /* Copies components of the address from OP to ADDR. */
800*e4b17023SJohn Marino
801*e4b17023SJohn Marino void
get_address_description(tree op,struct mem_address * addr)802*e4b17023SJohn Marino get_address_description (tree op, struct mem_address *addr)
803*e4b17023SJohn Marino {
804*e4b17023SJohn Marino if (TREE_CODE (TMR_BASE (op)) == ADDR_EXPR)
805*e4b17023SJohn Marino {
806*e4b17023SJohn Marino addr->symbol = TMR_BASE (op);
807*e4b17023SJohn Marino addr->base = TMR_INDEX2 (op);
808*e4b17023SJohn Marino }
809*e4b17023SJohn Marino else
810*e4b17023SJohn Marino {
811*e4b17023SJohn Marino addr->symbol = NULL_TREE;
812*e4b17023SJohn Marino if (TMR_INDEX2 (op))
813*e4b17023SJohn Marino {
814*e4b17023SJohn Marino gcc_assert (integer_zerop (TMR_BASE (op)));
815*e4b17023SJohn Marino addr->base = TMR_INDEX2 (op);
816*e4b17023SJohn Marino }
817*e4b17023SJohn Marino else
818*e4b17023SJohn Marino addr->base = TMR_BASE (op);
819*e4b17023SJohn Marino }
820*e4b17023SJohn Marino addr->index = TMR_INDEX (op);
821*e4b17023SJohn Marino addr->step = TMR_STEP (op);
822*e4b17023SJohn Marino addr->offset = TMR_OFFSET (op);
823*e4b17023SJohn Marino }
824*e4b17023SJohn Marino
825*e4b17023SJohn Marino /* Copies the additional information attached to target_mem_ref FROM to TO. */
826*e4b17023SJohn Marino
827*e4b17023SJohn Marino void
copy_mem_ref_info(tree to,tree from)828*e4b17023SJohn Marino copy_mem_ref_info (tree to, tree from)
829*e4b17023SJohn Marino {
830*e4b17023SJohn Marino /* And the info about the original reference. */
831*e4b17023SJohn Marino TREE_SIDE_EFFECTS (to) = TREE_SIDE_EFFECTS (from);
832*e4b17023SJohn Marino TREE_THIS_VOLATILE (to) = TREE_THIS_VOLATILE (from);
833*e4b17023SJohn Marino }
834*e4b17023SJohn Marino
835*e4b17023SJohn Marino /* Copies the reference information from OLD_REF to NEW_REF, where
836*e4b17023SJohn Marino NEW_REF should be either a MEM_REF or a TARGET_MEM_REF. */
837*e4b17023SJohn Marino
838*e4b17023SJohn Marino void
copy_ref_info(tree new_ref,tree old_ref)839*e4b17023SJohn Marino copy_ref_info (tree new_ref, tree old_ref)
840*e4b17023SJohn Marino {
841*e4b17023SJohn Marino tree new_ptr_base = NULL_TREE;
842*e4b17023SJohn Marino
843*e4b17023SJohn Marino gcc_assert (TREE_CODE (new_ref) == MEM_REF
844*e4b17023SJohn Marino || TREE_CODE (new_ref) == TARGET_MEM_REF);
845*e4b17023SJohn Marino
846*e4b17023SJohn Marino TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (old_ref);
847*e4b17023SJohn Marino TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (old_ref);
848*e4b17023SJohn Marino
849*e4b17023SJohn Marino new_ptr_base = TREE_OPERAND (new_ref, 0);
850*e4b17023SJohn Marino
851*e4b17023SJohn Marino /* We can transfer points-to information from an old pointer
852*e4b17023SJohn Marino or decl base to the new one. */
853*e4b17023SJohn Marino if (new_ptr_base
854*e4b17023SJohn Marino && TREE_CODE (new_ptr_base) == SSA_NAME
855*e4b17023SJohn Marino && !SSA_NAME_PTR_INFO (new_ptr_base))
856*e4b17023SJohn Marino {
857*e4b17023SJohn Marino tree base = get_base_address (old_ref);
858*e4b17023SJohn Marino if (!base)
859*e4b17023SJohn Marino ;
860*e4b17023SJohn Marino else if ((TREE_CODE (base) == MEM_REF
861*e4b17023SJohn Marino || TREE_CODE (base) == TARGET_MEM_REF)
862*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
863*e4b17023SJohn Marino && SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)))
864*e4b17023SJohn Marino {
865*e4b17023SJohn Marino struct ptr_info_def *new_pi;
866*e4b17023SJohn Marino duplicate_ssa_name_ptr_info
867*e4b17023SJohn Marino (new_ptr_base, SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)));
868*e4b17023SJohn Marino new_pi = SSA_NAME_PTR_INFO (new_ptr_base);
869*e4b17023SJohn Marino /* We have to be careful about transfering alignment information. */
870*e4b17023SJohn Marino if (TREE_CODE (old_ref) == MEM_REF
871*e4b17023SJohn Marino && !(TREE_CODE (new_ref) == TARGET_MEM_REF
872*e4b17023SJohn Marino && (TMR_INDEX2 (new_ref)
873*e4b17023SJohn Marino || (TMR_STEP (new_ref)
874*e4b17023SJohn Marino && (TREE_INT_CST_LOW (TMR_STEP (new_ref))
875*e4b17023SJohn Marino < new_pi->align)))))
876*e4b17023SJohn Marino {
877*e4b17023SJohn Marino new_pi->misalign += double_int_sub (mem_ref_offset (old_ref),
878*e4b17023SJohn Marino mem_ref_offset (new_ref)).low;
879*e4b17023SJohn Marino new_pi->misalign &= (new_pi->align - 1);
880*e4b17023SJohn Marino }
881*e4b17023SJohn Marino else
882*e4b17023SJohn Marino {
883*e4b17023SJohn Marino new_pi->align = 1;
884*e4b17023SJohn Marino new_pi->misalign = 0;
885*e4b17023SJohn Marino }
886*e4b17023SJohn Marino }
887*e4b17023SJohn Marino else if (TREE_CODE (base) == VAR_DECL
888*e4b17023SJohn Marino || TREE_CODE (base) == PARM_DECL
889*e4b17023SJohn Marino || TREE_CODE (base) == RESULT_DECL)
890*e4b17023SJohn Marino {
891*e4b17023SJohn Marino struct ptr_info_def *pi = get_ptr_info (new_ptr_base);
892*e4b17023SJohn Marino pt_solution_set_var (&pi->pt, base);
893*e4b17023SJohn Marino }
894*e4b17023SJohn Marino }
895*e4b17023SJohn Marino }
896*e4b17023SJohn Marino
897*e4b17023SJohn Marino /* Move constants in target_mem_ref REF to offset. Returns the new target
898*e4b17023SJohn Marino mem ref if anything changes, NULL_TREE otherwise. */
899*e4b17023SJohn Marino
900*e4b17023SJohn Marino tree
maybe_fold_tmr(tree ref)901*e4b17023SJohn Marino maybe_fold_tmr (tree ref)
902*e4b17023SJohn Marino {
903*e4b17023SJohn Marino struct mem_address addr;
904*e4b17023SJohn Marino bool changed = false;
905*e4b17023SJohn Marino tree ret, off;
906*e4b17023SJohn Marino
907*e4b17023SJohn Marino get_address_description (ref, &addr);
908*e4b17023SJohn Marino
909*e4b17023SJohn Marino if (addr.base
910*e4b17023SJohn Marino && TREE_CODE (addr.base) == INTEGER_CST
911*e4b17023SJohn Marino && !integer_zerop (addr.base))
912*e4b17023SJohn Marino {
913*e4b17023SJohn Marino addr.offset = fold_binary_to_constant (PLUS_EXPR,
914*e4b17023SJohn Marino TREE_TYPE (addr.offset),
915*e4b17023SJohn Marino addr.offset, addr.base);
916*e4b17023SJohn Marino addr.base = NULL_TREE;
917*e4b17023SJohn Marino changed = true;
918*e4b17023SJohn Marino }
919*e4b17023SJohn Marino
920*e4b17023SJohn Marino if (addr.symbol
921*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (addr.symbol, 0)) == MEM_REF)
922*e4b17023SJohn Marino {
923*e4b17023SJohn Marino addr.offset = fold_binary_to_constant
924*e4b17023SJohn Marino (PLUS_EXPR, TREE_TYPE (addr.offset),
925*e4b17023SJohn Marino addr.offset,
926*e4b17023SJohn Marino TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 1));
927*e4b17023SJohn Marino addr.symbol = TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 0);
928*e4b17023SJohn Marino changed = true;
929*e4b17023SJohn Marino }
930*e4b17023SJohn Marino else if (addr.symbol
931*e4b17023SJohn Marino && handled_component_p (TREE_OPERAND (addr.symbol, 0)))
932*e4b17023SJohn Marino {
933*e4b17023SJohn Marino HOST_WIDE_INT offset;
934*e4b17023SJohn Marino addr.symbol = build_fold_addr_expr
935*e4b17023SJohn Marino (get_addr_base_and_unit_offset
936*e4b17023SJohn Marino (TREE_OPERAND (addr.symbol, 0), &offset));
937*e4b17023SJohn Marino addr.offset = int_const_binop (PLUS_EXPR,
938*e4b17023SJohn Marino addr.offset, size_int (offset));
939*e4b17023SJohn Marino changed = true;
940*e4b17023SJohn Marino }
941*e4b17023SJohn Marino
942*e4b17023SJohn Marino if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
943*e4b17023SJohn Marino {
944*e4b17023SJohn Marino off = addr.index;
945*e4b17023SJohn Marino if (addr.step)
946*e4b17023SJohn Marino {
947*e4b17023SJohn Marino off = fold_binary_to_constant (MULT_EXPR, sizetype,
948*e4b17023SJohn Marino off, addr.step);
949*e4b17023SJohn Marino addr.step = NULL_TREE;
950*e4b17023SJohn Marino }
951*e4b17023SJohn Marino
952*e4b17023SJohn Marino addr.offset = fold_binary_to_constant (PLUS_EXPR,
953*e4b17023SJohn Marino TREE_TYPE (addr.offset),
954*e4b17023SJohn Marino addr.offset, off);
955*e4b17023SJohn Marino addr.index = NULL_TREE;
956*e4b17023SJohn Marino changed = true;
957*e4b17023SJohn Marino }
958*e4b17023SJohn Marino
959*e4b17023SJohn Marino if (!changed)
960*e4b17023SJohn Marino return NULL_TREE;
961*e4b17023SJohn Marino
962*e4b17023SJohn Marino /* If we have propagated something into this TARGET_MEM_REF and thus
963*e4b17023SJohn Marino ended up folding it, always create a new TARGET_MEM_REF regardless
964*e4b17023SJohn Marino if it is valid in this for on the target - the propagation result
965*e4b17023SJohn Marino wouldn't be anyway. */
966*e4b17023SJohn Marino ret = create_mem_ref_raw (TREE_TYPE (ref),
967*e4b17023SJohn Marino TREE_TYPE (addr.offset), &addr, false);
968*e4b17023SJohn Marino copy_mem_ref_info (ret, ref);
969*e4b17023SJohn Marino return ret;
970*e4b17023SJohn Marino }
971*e4b17023SJohn Marino
972*e4b17023SJohn Marino /* Dump PARTS to FILE. */
973*e4b17023SJohn Marino
974*e4b17023SJohn Marino extern void dump_mem_address (FILE *, struct mem_address *);
975*e4b17023SJohn Marino void
dump_mem_address(FILE * file,struct mem_address * parts)976*e4b17023SJohn Marino dump_mem_address (FILE *file, struct mem_address *parts)
977*e4b17023SJohn Marino {
978*e4b17023SJohn Marino if (parts->symbol)
979*e4b17023SJohn Marino {
980*e4b17023SJohn Marino fprintf (file, "symbol: ");
981*e4b17023SJohn Marino print_generic_expr (file, TREE_OPERAND (parts->symbol, 0), TDF_SLIM);
982*e4b17023SJohn Marino fprintf (file, "\n");
983*e4b17023SJohn Marino }
984*e4b17023SJohn Marino if (parts->base)
985*e4b17023SJohn Marino {
986*e4b17023SJohn Marino fprintf (file, "base: ");
987*e4b17023SJohn Marino print_generic_expr (file, parts->base, TDF_SLIM);
988*e4b17023SJohn Marino fprintf (file, "\n");
989*e4b17023SJohn Marino }
990*e4b17023SJohn Marino if (parts->index)
991*e4b17023SJohn Marino {
992*e4b17023SJohn Marino fprintf (file, "index: ");
993*e4b17023SJohn Marino print_generic_expr (file, parts->index, TDF_SLIM);
994*e4b17023SJohn Marino fprintf (file, "\n");
995*e4b17023SJohn Marino }
996*e4b17023SJohn Marino if (parts->step)
997*e4b17023SJohn Marino {
998*e4b17023SJohn Marino fprintf (file, "step: ");
999*e4b17023SJohn Marino print_generic_expr (file, parts->step, TDF_SLIM);
1000*e4b17023SJohn Marino fprintf (file, "\n");
1001*e4b17023SJohn Marino }
1002*e4b17023SJohn Marino if (parts->offset)
1003*e4b17023SJohn Marino {
1004*e4b17023SJohn Marino fprintf (file, "offset: ");
1005*e4b17023SJohn Marino print_generic_expr (file, parts->offset, TDF_SLIM);
1006*e4b17023SJohn Marino fprintf (file, "\n");
1007*e4b17023SJohn Marino }
1008*e4b17023SJohn Marino }
1009*e4b17023SJohn Marino
1010*e4b17023SJohn Marino #include "gt-tree-ssa-address.h"
1011