xref: /dflybsd-src/contrib/gcc-4.7/gcc/tree-ssa-address.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
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