xref: /dragonfly/contrib/gcc-4.7/gcc/gimple-fold.c (revision 5ce9237c)
1e4b17023SJohn Marino /* Statement simplification on GIMPLE.
2e4b17023SJohn Marino    Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
3e4b17023SJohn Marino    Split out from tree-ssa-ccp.c.
4e4b17023SJohn Marino 
5e4b17023SJohn Marino This file is part of GCC.
6e4b17023SJohn Marino 
7e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it
8e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
9e4b17023SJohn Marino Free Software Foundation; either version 3, or (at your option) any
10e4b17023SJohn Marino later version.
11e4b17023SJohn Marino 
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
13e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15e4b17023SJohn Marino for more details.
16e4b17023SJohn Marino 
17e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
19e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
20e4b17023SJohn Marino 
21e4b17023SJohn Marino #include "config.h"
22e4b17023SJohn Marino #include "system.h"
23e4b17023SJohn Marino #include "coretypes.h"
24e4b17023SJohn Marino #include "tm.h"
25e4b17023SJohn Marino #include "tree.h"
26e4b17023SJohn Marino #include "flags.h"
27e4b17023SJohn Marino #include "function.h"
28e4b17023SJohn Marino #include "tree-dump.h"
29e4b17023SJohn Marino #include "tree-flow.h"
30e4b17023SJohn Marino #include "tree-pass.h"
31e4b17023SJohn Marino #include "tree-ssa-propagate.h"
32e4b17023SJohn Marino #include "target.h"
33e4b17023SJohn Marino #include "gimple-fold.h"
34e4b17023SJohn Marino 
35e4b17023SJohn Marino /* Return true when DECL can be referenced from current unit.
36e4b17023SJohn Marino    We can get declarations that are not possible to reference for
37e4b17023SJohn Marino    various reasons:
38e4b17023SJohn Marino 
39e4b17023SJohn Marino      1) When analyzing C++ virtual tables.
40e4b17023SJohn Marino 	C++ virtual tables do have known constructors even
41e4b17023SJohn Marino 	when they are keyed to other compilation unit.
42e4b17023SJohn Marino 	Those tables can contain pointers to methods and vars
43e4b17023SJohn Marino 	in other units.  Those methods have both STATIC and EXTERNAL
44e4b17023SJohn Marino 	set.
45e4b17023SJohn Marino      2) In WHOPR mode devirtualization might lead to reference
46e4b17023SJohn Marino 	to method that was partitioned elsehwere.
47e4b17023SJohn Marino 	In this case we have static VAR_DECL or FUNCTION_DECL
48e4b17023SJohn Marino 	that has no corresponding callgraph/varpool node
49e4b17023SJohn Marino 	declaring the body.
50e4b17023SJohn Marino      3) COMDAT functions referred by external vtables that
51e4b17023SJohn Marino         we devirtualize only during final copmilation stage.
52e4b17023SJohn Marino         At this time we already decided that we will not output
53e4b17023SJohn Marino         the function body and thus we can't reference the symbol
54e4b17023SJohn Marino         directly.  */
55e4b17023SJohn Marino 
56e4b17023SJohn Marino static bool
can_refer_decl_in_current_unit_p(tree decl)57e4b17023SJohn Marino can_refer_decl_in_current_unit_p (tree decl)
58e4b17023SJohn Marino {
59e4b17023SJohn Marino   struct varpool_node *vnode;
60e4b17023SJohn Marino   struct cgraph_node *node;
61e4b17023SJohn Marino 
62e4b17023SJohn Marino   if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
63e4b17023SJohn Marino     return true;
64e4b17023SJohn Marino   /* External flag is set, so we deal with C++ reference
65e4b17023SJohn Marino      to static object from other file.  */
66e4b17023SJohn Marino   if (DECL_EXTERNAL (decl) && TREE_STATIC (decl)
67e4b17023SJohn Marino       && TREE_CODE (decl) == VAR_DECL)
68e4b17023SJohn Marino     {
69e4b17023SJohn Marino       /* Just be sure it is not big in frontend setting
70e4b17023SJohn Marino 	 flags incorrectly.  Those variables should never
71e4b17023SJohn Marino 	 be finalized.  */
72e4b17023SJohn Marino       gcc_checking_assert (!(vnode = varpool_get_node (decl))
73e4b17023SJohn Marino 			   || !vnode->finalized);
74e4b17023SJohn Marino       return false;
75e4b17023SJohn Marino     }
76e4b17023SJohn Marino   /* When function is public, we always can introduce new reference.
77e4b17023SJohn Marino      Exception are the COMDAT functions where introducing a direct
78e4b17023SJohn Marino      reference imply need to include function body in the curren tunit.  */
79e4b17023SJohn Marino   if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
80e4b17023SJohn Marino     return true;
81e4b17023SJohn Marino   /* We are not at ltrans stage; so don't worry about WHOPR.
82e4b17023SJohn Marino      Also when still gimplifying all referred comdat functions will be
83e4b17023SJohn Marino      produced.
84e4b17023SJohn Marino      ??? as observed in PR20991 for already optimized out comdat virtual functions
85e4b17023SJohn Marino      we may not neccesarily give up because the copy will be output elsewhere when
86e4b17023SJohn Marino      corresponding vtable is output.  */
87e4b17023SJohn Marino   if (!flag_ltrans && (!DECL_COMDAT (decl) || !cgraph_function_flags_ready))
88e4b17023SJohn Marino     return true;
89e4b17023SJohn Marino   /* If we already output the function body, we are safe.  */
90e4b17023SJohn Marino   if (TREE_ASM_WRITTEN (decl))
91e4b17023SJohn Marino     return true;
92e4b17023SJohn Marino   if (TREE_CODE (decl) == FUNCTION_DECL)
93e4b17023SJohn Marino     {
94e4b17023SJohn Marino       node = cgraph_get_node (decl);
95e4b17023SJohn Marino       /* Check that we still have function body and that we didn't took
96e4b17023SJohn Marino          the decision to eliminate offline copy of the function yet.
97e4b17023SJohn Marino          The second is important when devirtualization happens during final
98e4b17023SJohn Marino          compilation stage when making a new reference no longer makes callee
99e4b17023SJohn Marino          to be compiled.  */
100e4b17023SJohn Marino       if (!node || !node->analyzed || node->global.inlined_to)
101e4b17023SJohn Marino 	return false;
102e4b17023SJohn Marino     }
103e4b17023SJohn Marino   else if (TREE_CODE (decl) == VAR_DECL)
104e4b17023SJohn Marino     {
105e4b17023SJohn Marino       vnode = varpool_get_node (decl);
106e4b17023SJohn Marino       if (!vnode || !vnode->finalized)
107e4b17023SJohn Marino 	return false;
108e4b17023SJohn Marino     }
109e4b17023SJohn Marino   return true;
110e4b17023SJohn Marino }
111e4b17023SJohn Marino 
112e4b17023SJohn Marino /* CVAL is value taken from DECL_INITIAL of variable.  Try to transform it into
113e4b17023SJohn Marino    acceptable form for is_gimple_min_invariant.   */
114e4b17023SJohn Marino 
115e4b17023SJohn Marino tree
canonicalize_constructor_val(tree cval)116e4b17023SJohn Marino canonicalize_constructor_val (tree cval)
117e4b17023SJohn Marino {
118*5ce9237cSJohn Marino   tree orig_cval = cval;
119*5ce9237cSJohn Marino   STRIP_NOPS (cval);
120e4b17023SJohn Marino   if (TREE_CODE (cval) == POINTER_PLUS_EXPR
121e4b17023SJohn Marino       && TREE_CODE (TREE_OPERAND (cval, 1)) == INTEGER_CST)
122e4b17023SJohn Marino     {
123e4b17023SJohn Marino       tree ptr = TREE_OPERAND (cval, 0);
124e4b17023SJohn Marino       if (is_gimple_min_invariant (ptr))
125e4b17023SJohn Marino 	cval = build1_loc (EXPR_LOCATION (cval),
126e4b17023SJohn Marino 			   ADDR_EXPR, TREE_TYPE (ptr),
127e4b17023SJohn Marino 			   fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (ptr)),
128e4b17023SJohn Marino 					ptr,
129e4b17023SJohn Marino 					fold_convert (ptr_type_node,
130e4b17023SJohn Marino 						      TREE_OPERAND (cval, 1))));
131e4b17023SJohn Marino     }
132e4b17023SJohn Marino   if (TREE_CODE (cval) == ADDR_EXPR)
133e4b17023SJohn Marino     {
134e4b17023SJohn Marino       tree base = get_base_address (TREE_OPERAND (cval, 0));
135e4b17023SJohn Marino 
136e4b17023SJohn Marino       if (base
137e4b17023SJohn Marino 	  && (TREE_CODE (base) == VAR_DECL
138e4b17023SJohn Marino 	      || TREE_CODE (base) == FUNCTION_DECL)
139e4b17023SJohn Marino 	  && !can_refer_decl_in_current_unit_p (base))
140e4b17023SJohn Marino 	return NULL_TREE;
141e4b17023SJohn Marino       if (base && TREE_CODE (base) == VAR_DECL)
142e4b17023SJohn Marino 	{
143e4b17023SJohn Marino 	  TREE_ADDRESSABLE (base) = 1;
144e4b17023SJohn Marino 	  if (cfun && gimple_referenced_vars (cfun))
145e4b17023SJohn Marino 	    add_referenced_var (base);
146e4b17023SJohn Marino 	}
147e4b17023SJohn Marino       /* Fixup types in global initializers.  */
148e4b17023SJohn Marino       if (TREE_TYPE (TREE_TYPE (cval)) != TREE_TYPE (TREE_OPERAND (cval, 0)))
149e4b17023SJohn Marino 	cval = build_fold_addr_expr (TREE_OPERAND (cval, 0));
150*5ce9237cSJohn Marino 
151*5ce9237cSJohn Marino       if (!useless_type_conversion_p (TREE_TYPE (orig_cval), TREE_TYPE (cval)))
152*5ce9237cSJohn Marino 	cval = fold_convert (TREE_TYPE (orig_cval), cval);
153e4b17023SJohn Marino       return cval;
154e4b17023SJohn Marino     }
155*5ce9237cSJohn Marino   return orig_cval;
156*5ce9237cSJohn Marino }
157e4b17023SJohn Marino 
158e4b17023SJohn Marino /* If SYM is a constant variable with known value, return the value.
159e4b17023SJohn Marino    NULL_TREE is returned otherwise.  */
160e4b17023SJohn Marino 
161e4b17023SJohn Marino tree
get_symbol_constant_value(tree sym)162e4b17023SJohn Marino get_symbol_constant_value (tree sym)
163e4b17023SJohn Marino {
164e4b17023SJohn Marino   if (const_value_known_p (sym))
165e4b17023SJohn Marino     {
166e4b17023SJohn Marino       tree val = DECL_INITIAL (sym);
167e4b17023SJohn Marino       if (val)
168e4b17023SJohn Marino 	{
169e4b17023SJohn Marino 	  val = canonicalize_constructor_val (val);
170e4b17023SJohn Marino 	  if (val && is_gimple_min_invariant (val))
171e4b17023SJohn Marino 	    return val;
172e4b17023SJohn Marino 	  else
173e4b17023SJohn Marino 	    return NULL_TREE;
174e4b17023SJohn Marino 	}
175e4b17023SJohn Marino       /* Variables declared 'const' without an initializer
176e4b17023SJohn Marino 	 have zero as the initializer if they may not be
177e4b17023SJohn Marino 	 overridden at link or run time.  */
178e4b17023SJohn Marino       if (!val
179e4b17023SJohn Marino           && (INTEGRAL_TYPE_P (TREE_TYPE (sym))
180e4b17023SJohn Marino 	       || SCALAR_FLOAT_TYPE_P (TREE_TYPE (sym))))
181e4b17023SJohn Marino 	return build_zero_cst (TREE_TYPE (sym));
182e4b17023SJohn Marino     }
183e4b17023SJohn Marino 
184e4b17023SJohn Marino   return NULL_TREE;
185e4b17023SJohn Marino }
186e4b17023SJohn Marino 
187e4b17023SJohn Marino 
188e4b17023SJohn Marino 
189e4b17023SJohn Marino /* Subroutine of fold_stmt.  We perform several simplifications of the
190e4b17023SJohn Marino    memory reference tree EXPR and make sure to re-gimplify them properly
191e4b17023SJohn Marino    after propagation of constant addresses.  IS_LHS is true if the
192e4b17023SJohn Marino    reference is supposed to be an lvalue.  */
193e4b17023SJohn Marino 
194e4b17023SJohn Marino static tree
maybe_fold_reference(tree expr,bool is_lhs)195e4b17023SJohn Marino maybe_fold_reference (tree expr, bool is_lhs)
196e4b17023SJohn Marino {
197e4b17023SJohn Marino   tree *t = &expr;
198e4b17023SJohn Marino   tree result;
199e4b17023SJohn Marino 
200e4b17023SJohn Marino   if ((TREE_CODE (expr) == VIEW_CONVERT_EXPR
201e4b17023SJohn Marino        || TREE_CODE (expr) == REALPART_EXPR
202e4b17023SJohn Marino        || TREE_CODE (expr) == IMAGPART_EXPR)
203e4b17023SJohn Marino       && CONSTANT_CLASS_P (TREE_OPERAND (expr, 0)))
204e4b17023SJohn Marino     return fold_unary_loc (EXPR_LOCATION (expr),
205e4b17023SJohn Marino 			   TREE_CODE (expr),
206e4b17023SJohn Marino 			   TREE_TYPE (expr),
207e4b17023SJohn Marino 			   TREE_OPERAND (expr, 0));
208e4b17023SJohn Marino   else if (TREE_CODE (expr) == BIT_FIELD_REF
209e4b17023SJohn Marino 	   && CONSTANT_CLASS_P (TREE_OPERAND (expr, 0)))
210e4b17023SJohn Marino     return fold_ternary_loc (EXPR_LOCATION (expr),
211e4b17023SJohn Marino 			     TREE_CODE (expr),
212e4b17023SJohn Marino 			     TREE_TYPE (expr),
213e4b17023SJohn Marino 			     TREE_OPERAND (expr, 0),
214e4b17023SJohn Marino 			     TREE_OPERAND (expr, 1),
215e4b17023SJohn Marino 			     TREE_OPERAND (expr, 2));
216e4b17023SJohn Marino 
217e4b17023SJohn Marino   while (handled_component_p (*t))
218e4b17023SJohn Marino     t = &TREE_OPERAND (*t, 0);
219e4b17023SJohn Marino 
220e4b17023SJohn Marino   /* Canonicalize MEM_REFs invariant address operand.  Do this first
221e4b17023SJohn Marino      to avoid feeding non-canonical MEM_REFs elsewhere.  */
222e4b17023SJohn Marino   if (TREE_CODE (*t) == MEM_REF
223e4b17023SJohn Marino       && !is_gimple_mem_ref_addr (TREE_OPERAND (*t, 0)))
224e4b17023SJohn Marino     {
225e4b17023SJohn Marino       bool volatile_p = TREE_THIS_VOLATILE (*t);
226e4b17023SJohn Marino       tree tem = fold_binary (MEM_REF, TREE_TYPE (*t),
227e4b17023SJohn Marino 			      TREE_OPERAND (*t, 0),
228e4b17023SJohn Marino 			      TREE_OPERAND (*t, 1));
229e4b17023SJohn Marino       if (tem)
230e4b17023SJohn Marino 	{
231e4b17023SJohn Marino 	  TREE_THIS_VOLATILE (tem) = volatile_p;
232e4b17023SJohn Marino 	  *t = tem;
233e4b17023SJohn Marino 	  tem = maybe_fold_reference (expr, is_lhs);
234e4b17023SJohn Marino 	  if (tem)
235e4b17023SJohn Marino 	    return tem;
236e4b17023SJohn Marino 	  return expr;
237e4b17023SJohn Marino 	}
238e4b17023SJohn Marino     }
239e4b17023SJohn Marino 
240e4b17023SJohn Marino   if (!is_lhs
241e4b17023SJohn Marino       && (result = fold_const_aggregate_ref (expr))
242e4b17023SJohn Marino       && is_gimple_min_invariant (result))
243e4b17023SJohn Marino     return result;
244e4b17023SJohn Marino 
245e4b17023SJohn Marino   /* Fold back MEM_REFs to reference trees.  */
246e4b17023SJohn Marino   if (TREE_CODE (*t) == MEM_REF
247e4b17023SJohn Marino       && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
248e4b17023SJohn Marino       && integer_zerop (TREE_OPERAND (*t, 1))
249e4b17023SJohn Marino       && (TREE_THIS_VOLATILE (*t)
250e4b17023SJohn Marino 	  == TREE_THIS_VOLATILE (TREE_OPERAND (TREE_OPERAND (*t, 0), 0)))
251e4b17023SJohn Marino       && !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*t, 1)))
252e4b17023SJohn Marino       && (TYPE_MAIN_VARIANT (TREE_TYPE (*t))
253e4b17023SJohn Marino 	  == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (*t, 1)))))
254e4b17023SJohn Marino       /* We have to look out here to not drop a required conversion
255e4b17023SJohn Marino 	 from the rhs to the lhs if is_lhs, but we don't have the
256e4b17023SJohn Marino 	 rhs here to verify that.  Thus require strict type
257e4b17023SJohn Marino 	 compatibility.  */
258e4b17023SJohn Marino       && types_compatible_p (TREE_TYPE (*t),
259e4b17023SJohn Marino 			     TREE_TYPE (TREE_OPERAND
260e4b17023SJohn Marino 					(TREE_OPERAND (*t, 0), 0))))
261e4b17023SJohn Marino     {
262e4b17023SJohn Marino       tree tem;
263e4b17023SJohn Marino       *t = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
264e4b17023SJohn Marino       tem = maybe_fold_reference (expr, is_lhs);
265e4b17023SJohn Marino       if (tem)
266e4b17023SJohn Marino 	return tem;
267e4b17023SJohn Marino       return expr;
268e4b17023SJohn Marino     }
269e4b17023SJohn Marino   else if (TREE_CODE (*t) == TARGET_MEM_REF)
270e4b17023SJohn Marino     {
271e4b17023SJohn Marino       tree tem = maybe_fold_tmr (*t);
272e4b17023SJohn Marino       if (tem)
273e4b17023SJohn Marino 	{
274e4b17023SJohn Marino 	  *t = tem;
275e4b17023SJohn Marino 	  tem = maybe_fold_reference (expr, is_lhs);
276e4b17023SJohn Marino 	  if (tem)
277e4b17023SJohn Marino 	    return tem;
278e4b17023SJohn Marino 	  return expr;
279e4b17023SJohn Marino 	}
280e4b17023SJohn Marino     }
281e4b17023SJohn Marino 
282e4b17023SJohn Marino   return NULL_TREE;
283e4b17023SJohn Marino }
284e4b17023SJohn Marino 
285e4b17023SJohn Marino 
286e4b17023SJohn Marino /* Attempt to fold an assignment statement pointed-to by SI.  Returns a
287e4b17023SJohn Marino    replacement rhs for the statement or NULL_TREE if no simplification
288e4b17023SJohn Marino    could be made.  It is assumed that the operands have been previously
289e4b17023SJohn Marino    folded.  */
290e4b17023SJohn Marino 
291e4b17023SJohn Marino static tree
fold_gimple_assign(gimple_stmt_iterator * si)292e4b17023SJohn Marino fold_gimple_assign (gimple_stmt_iterator *si)
293e4b17023SJohn Marino {
294e4b17023SJohn Marino   gimple stmt = gsi_stmt (*si);
295e4b17023SJohn Marino   enum tree_code subcode = gimple_assign_rhs_code (stmt);
296e4b17023SJohn Marino   location_t loc = gimple_location (stmt);
297e4b17023SJohn Marino 
298e4b17023SJohn Marino   tree result = NULL_TREE;
299e4b17023SJohn Marino 
300e4b17023SJohn Marino   switch (get_gimple_rhs_class (subcode))
301e4b17023SJohn Marino     {
302e4b17023SJohn Marino     case GIMPLE_SINGLE_RHS:
303e4b17023SJohn Marino       {
304e4b17023SJohn Marino         tree rhs = gimple_assign_rhs1 (stmt);
305e4b17023SJohn Marino 
306e4b17023SJohn Marino 	if (REFERENCE_CLASS_P (rhs))
307e4b17023SJohn Marino 	  return maybe_fold_reference (rhs, false);
308e4b17023SJohn Marino 
309e4b17023SJohn Marino 	else if (TREE_CODE (rhs) == ADDR_EXPR)
310e4b17023SJohn Marino 	  {
311e4b17023SJohn Marino 	    tree ref = TREE_OPERAND (rhs, 0);
312e4b17023SJohn Marino 	    tree tem = maybe_fold_reference (ref, true);
313e4b17023SJohn Marino 	    if (tem
314e4b17023SJohn Marino 		&& TREE_CODE (tem) == MEM_REF
315e4b17023SJohn Marino 		&& integer_zerop (TREE_OPERAND (tem, 1)))
316e4b17023SJohn Marino 	      result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (tem, 0));
317e4b17023SJohn Marino 	    else if (tem)
318e4b17023SJohn Marino 	      result = fold_convert (TREE_TYPE (rhs),
319e4b17023SJohn Marino 				     build_fold_addr_expr_loc (loc, tem));
320e4b17023SJohn Marino 	    else if (TREE_CODE (ref) == MEM_REF
321e4b17023SJohn Marino 		     && integer_zerop (TREE_OPERAND (ref, 1)))
322e4b17023SJohn Marino 	      result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (ref, 0));
323e4b17023SJohn Marino 	  }
324e4b17023SJohn Marino 
325e4b17023SJohn Marino 	else if (TREE_CODE (rhs) == CONSTRUCTOR
326e4b17023SJohn Marino 		 && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE
327e4b17023SJohn Marino 		 && (CONSTRUCTOR_NELTS (rhs)
328e4b17023SJohn Marino 		     == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs))))
329e4b17023SJohn Marino 	  {
330e4b17023SJohn Marino 	    /* Fold a constant vector CONSTRUCTOR to VECTOR_CST.  */
331e4b17023SJohn Marino 	    unsigned i;
332e4b17023SJohn Marino 	    tree val;
333e4b17023SJohn Marino 
334e4b17023SJohn Marino 	    FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val)
335e4b17023SJohn Marino 	      if (TREE_CODE (val) != INTEGER_CST
336e4b17023SJohn Marino 		  && TREE_CODE (val) != REAL_CST
337e4b17023SJohn Marino 		  && TREE_CODE (val) != FIXED_CST)
338e4b17023SJohn Marino 		return NULL_TREE;
339e4b17023SJohn Marino 
340e4b17023SJohn Marino 	    return build_vector_from_ctor (TREE_TYPE (rhs),
341e4b17023SJohn Marino 					   CONSTRUCTOR_ELTS (rhs));
342e4b17023SJohn Marino 	  }
343e4b17023SJohn Marino 
344e4b17023SJohn Marino 	else if (DECL_P (rhs))
345e4b17023SJohn Marino 	  return unshare_expr (get_symbol_constant_value (rhs));
346e4b17023SJohn Marino 
347e4b17023SJohn Marino         /* If we couldn't fold the RHS, hand over to the generic
348e4b17023SJohn Marino            fold routines.  */
349e4b17023SJohn Marino         if (result == NULL_TREE)
350e4b17023SJohn Marino           result = fold (rhs);
351e4b17023SJohn Marino 
352e4b17023SJohn Marino         /* Strip away useless type conversions.  Both the NON_LVALUE_EXPR
353e4b17023SJohn Marino            that may have been added by fold, and "useless" type
354e4b17023SJohn Marino            conversions that might now be apparent due to propagation.  */
355e4b17023SJohn Marino         STRIP_USELESS_TYPE_CONVERSION (result);
356e4b17023SJohn Marino 
357e4b17023SJohn Marino         if (result != rhs && valid_gimple_rhs_p (result))
358e4b17023SJohn Marino 	  return result;
359e4b17023SJohn Marino 
360e4b17023SJohn Marino 	return NULL_TREE;
361e4b17023SJohn Marino       }
362e4b17023SJohn Marino       break;
363e4b17023SJohn Marino 
364e4b17023SJohn Marino     case GIMPLE_UNARY_RHS:
365e4b17023SJohn Marino       {
366e4b17023SJohn Marino 	tree rhs = gimple_assign_rhs1 (stmt);
367e4b17023SJohn Marino 
368e4b17023SJohn Marino 	result = fold_unary_loc (loc, subcode, gimple_expr_type (stmt), rhs);
369e4b17023SJohn Marino 	if (result)
370e4b17023SJohn Marino 	  {
371e4b17023SJohn Marino 	    /* If the operation was a conversion do _not_ mark a
372e4b17023SJohn Marino 	       resulting constant with TREE_OVERFLOW if the original
373e4b17023SJohn Marino 	       constant was not.  These conversions have implementation
374e4b17023SJohn Marino 	       defined behavior and retaining the TREE_OVERFLOW flag
375e4b17023SJohn Marino 	       here would confuse later passes such as VRP.  */
376e4b17023SJohn Marino 	    if (CONVERT_EXPR_CODE_P (subcode)
377e4b17023SJohn Marino 		&& TREE_CODE (result) == INTEGER_CST
378e4b17023SJohn Marino 		&& TREE_CODE (rhs) == INTEGER_CST)
379e4b17023SJohn Marino 	      TREE_OVERFLOW (result) = TREE_OVERFLOW (rhs);
380e4b17023SJohn Marino 
381e4b17023SJohn Marino 	    STRIP_USELESS_TYPE_CONVERSION (result);
382e4b17023SJohn Marino 	    if (valid_gimple_rhs_p (result))
383e4b17023SJohn Marino 	      return result;
384e4b17023SJohn Marino 	  }
385e4b17023SJohn Marino       }
386e4b17023SJohn Marino       break;
387e4b17023SJohn Marino 
388e4b17023SJohn Marino     case GIMPLE_BINARY_RHS:
389e4b17023SJohn Marino       /* Try to canonicalize for boolean-typed X the comparisons
390e4b17023SJohn Marino 	 X == 0, X == 1, X != 0, and X != 1.  */
391e4b17023SJohn Marino       if (gimple_assign_rhs_code (stmt) == EQ_EXPR
392e4b17023SJohn Marino 	  || gimple_assign_rhs_code (stmt) == NE_EXPR)
393e4b17023SJohn Marino         {
394e4b17023SJohn Marino 	  tree lhs = gimple_assign_lhs (stmt);
395e4b17023SJohn Marino 	  tree op1 = gimple_assign_rhs1 (stmt);
396e4b17023SJohn Marino 	  tree op2 = gimple_assign_rhs2 (stmt);
397e4b17023SJohn Marino 	  tree type = TREE_TYPE (op1);
398e4b17023SJohn Marino 
399e4b17023SJohn Marino 	  /* Check whether the comparison operands are of the same boolean
400e4b17023SJohn Marino 	     type as the result type is.
401e4b17023SJohn Marino 	     Check that second operand is an integer-constant with value
402e4b17023SJohn Marino 	     one or zero.  */
403e4b17023SJohn Marino 	  if (TREE_CODE (op2) == INTEGER_CST
404e4b17023SJohn Marino 	      && (integer_zerop (op2) || integer_onep (op2))
405e4b17023SJohn Marino 	      && useless_type_conversion_p (TREE_TYPE (lhs), type))
406e4b17023SJohn Marino 	    {
407e4b17023SJohn Marino 	      enum tree_code cmp_code = gimple_assign_rhs_code (stmt);
408e4b17023SJohn Marino 	      bool is_logical_not = false;
409e4b17023SJohn Marino 
410e4b17023SJohn Marino 	      /* X == 0 and X != 1 is a logical-not.of X
411e4b17023SJohn Marino 	         X == 1 and X != 0 is X  */
412e4b17023SJohn Marino 	      if ((cmp_code == EQ_EXPR && integer_zerop (op2))
413e4b17023SJohn Marino 	          || (cmp_code == NE_EXPR && integer_onep (op2)))
414e4b17023SJohn Marino 	        is_logical_not = true;
415e4b17023SJohn Marino 
416e4b17023SJohn Marino 	      if (is_logical_not == false)
417e4b17023SJohn Marino 	        result = op1;
418e4b17023SJohn Marino 	      /* Only for one-bit precision typed X the transformation
419e4b17023SJohn Marino 	         !X -> ~X is valied.  */
420e4b17023SJohn Marino 	      else if (TYPE_PRECISION (type) == 1)
421e4b17023SJohn Marino 		result = build1_loc (gimple_location (stmt), BIT_NOT_EXPR,
422e4b17023SJohn Marino 				     type, op1);
423e4b17023SJohn Marino 	      /* Otherwise we use !X -> X ^ 1.  */
424e4b17023SJohn Marino 	      else
425e4b17023SJohn Marino 	        result = build2_loc (gimple_location (stmt), BIT_XOR_EXPR,
426e4b17023SJohn Marino 				     type, op1, build_int_cst (type, 1));
427e4b17023SJohn Marino 
428e4b17023SJohn Marino 	    }
429e4b17023SJohn Marino 	}
430e4b17023SJohn Marino 
431e4b17023SJohn Marino       if (!result)
432e4b17023SJohn Marino         result = fold_binary_loc (loc, subcode,
433e4b17023SJohn Marino 				  TREE_TYPE (gimple_assign_lhs (stmt)),
434e4b17023SJohn Marino 				  gimple_assign_rhs1 (stmt),
435e4b17023SJohn Marino 				  gimple_assign_rhs2 (stmt));
436e4b17023SJohn Marino 
437e4b17023SJohn Marino       if (result)
438e4b17023SJohn Marino         {
439e4b17023SJohn Marino           STRIP_USELESS_TYPE_CONVERSION (result);
440e4b17023SJohn Marino           if (valid_gimple_rhs_p (result))
441e4b17023SJohn Marino 	    return result;
442e4b17023SJohn Marino         }
443e4b17023SJohn Marino       break;
444e4b17023SJohn Marino 
445e4b17023SJohn Marino     case GIMPLE_TERNARY_RHS:
446e4b17023SJohn Marino       /* Try to fold a conditional expression.  */
447e4b17023SJohn Marino       if (gimple_assign_rhs_code (stmt) == COND_EXPR)
448e4b17023SJohn Marino 	{
449e4b17023SJohn Marino 	  tree op0 = gimple_assign_rhs1 (stmt);
450e4b17023SJohn Marino 	  tree tem;
451e4b17023SJohn Marino 	  bool set = false;
452e4b17023SJohn Marino 	  location_t cond_loc = gimple_location (stmt);
453e4b17023SJohn Marino 
454e4b17023SJohn Marino 	  if (COMPARISON_CLASS_P (op0))
455e4b17023SJohn Marino 	    {
456e4b17023SJohn Marino 	      fold_defer_overflow_warnings ();
457e4b17023SJohn Marino 	      tem = fold_binary_loc (cond_loc,
458e4b17023SJohn Marino 				     TREE_CODE (op0), TREE_TYPE (op0),
459e4b17023SJohn Marino 				     TREE_OPERAND (op0, 0),
460e4b17023SJohn Marino 				     TREE_OPERAND (op0, 1));
461e4b17023SJohn Marino 	      /* This is actually a conditional expression, not a GIMPLE
462e4b17023SJohn Marino 		 conditional statement, however, the valid_gimple_rhs_p
463e4b17023SJohn Marino 		 test still applies.  */
464e4b17023SJohn Marino 	      set = (tem && is_gimple_condexpr (tem)
465e4b17023SJohn Marino 		     && valid_gimple_rhs_p (tem));
466e4b17023SJohn Marino 	      fold_undefer_overflow_warnings (set, stmt, 0);
467e4b17023SJohn Marino 	    }
468e4b17023SJohn Marino 	  else if (is_gimple_min_invariant (op0))
469e4b17023SJohn Marino 	    {
470e4b17023SJohn Marino 	      tem = op0;
471e4b17023SJohn Marino 	      set = true;
472e4b17023SJohn Marino 	    }
473e4b17023SJohn Marino 	  else
474e4b17023SJohn Marino 	    return NULL_TREE;
475e4b17023SJohn Marino 
476e4b17023SJohn Marino 	  if (set)
477e4b17023SJohn Marino 	    result = fold_build3_loc (cond_loc, COND_EXPR,
478e4b17023SJohn Marino 				      TREE_TYPE (gimple_assign_lhs (stmt)), tem,
479e4b17023SJohn Marino 				      gimple_assign_rhs2 (stmt),
480e4b17023SJohn Marino 				      gimple_assign_rhs3 (stmt));
481e4b17023SJohn Marino 	}
482e4b17023SJohn Marino 
483e4b17023SJohn Marino       if (!result)
484e4b17023SJohn Marino 	result = fold_ternary_loc (loc, subcode,
485e4b17023SJohn Marino 				   TREE_TYPE (gimple_assign_lhs (stmt)),
486e4b17023SJohn Marino 				   gimple_assign_rhs1 (stmt),
487e4b17023SJohn Marino 				   gimple_assign_rhs2 (stmt),
488e4b17023SJohn Marino 				   gimple_assign_rhs3 (stmt));
489e4b17023SJohn Marino 
490e4b17023SJohn Marino       if (result)
491e4b17023SJohn Marino         {
492e4b17023SJohn Marino           STRIP_USELESS_TYPE_CONVERSION (result);
493e4b17023SJohn Marino           if (valid_gimple_rhs_p (result))
494e4b17023SJohn Marino 	    return result;
495e4b17023SJohn Marino         }
496e4b17023SJohn Marino       break;
497e4b17023SJohn Marino 
498e4b17023SJohn Marino     case GIMPLE_INVALID_RHS:
499e4b17023SJohn Marino       gcc_unreachable ();
500e4b17023SJohn Marino     }
501e4b17023SJohn Marino 
502e4b17023SJohn Marino   return NULL_TREE;
503e4b17023SJohn Marino }
504e4b17023SJohn Marino 
505e4b17023SJohn Marino /* Attempt to fold a conditional statement. Return true if any changes were
506e4b17023SJohn Marino    made. We only attempt to fold the condition expression, and do not perform
507e4b17023SJohn Marino    any transformation that would require alteration of the cfg.  It is
508e4b17023SJohn Marino    assumed that the operands have been previously folded.  */
509e4b17023SJohn Marino 
510e4b17023SJohn Marino static bool
fold_gimple_cond(gimple stmt)511e4b17023SJohn Marino fold_gimple_cond (gimple stmt)
512e4b17023SJohn Marino {
513e4b17023SJohn Marino   tree result = fold_binary_loc (gimple_location (stmt),
514e4b17023SJohn Marino 			     gimple_cond_code (stmt),
515e4b17023SJohn Marino                              boolean_type_node,
516e4b17023SJohn Marino                              gimple_cond_lhs (stmt),
517e4b17023SJohn Marino                              gimple_cond_rhs (stmt));
518e4b17023SJohn Marino 
519e4b17023SJohn Marino   if (result)
520e4b17023SJohn Marino     {
521e4b17023SJohn Marino       STRIP_USELESS_TYPE_CONVERSION (result);
522e4b17023SJohn Marino       if (is_gimple_condexpr (result) && valid_gimple_rhs_p (result))
523e4b17023SJohn Marino         {
524e4b17023SJohn Marino           gimple_cond_set_condition_from_tree (stmt, result);
525e4b17023SJohn Marino           return true;
526e4b17023SJohn Marino         }
527e4b17023SJohn Marino     }
528e4b17023SJohn Marino 
529e4b17023SJohn Marino   return false;
530e4b17023SJohn Marino }
531e4b17023SJohn Marino 
532e4b17023SJohn Marino /* Convert EXPR into a GIMPLE value suitable for substitution on the
533e4b17023SJohn Marino    RHS of an assignment.  Insert the necessary statements before
534e4b17023SJohn Marino    iterator *SI_P.  The statement at *SI_P, which must be a GIMPLE_CALL
535e4b17023SJohn Marino    is replaced.  If the call is expected to produces a result, then it
536e4b17023SJohn Marino    is replaced by an assignment of the new RHS to the result variable.
537e4b17023SJohn Marino    If the result is to be ignored, then the call is replaced by a
538e4b17023SJohn Marino    GIMPLE_NOP.  A proper VDEF chain is retained by making the first
539e4b17023SJohn Marino    VUSE and the last VDEF of the whole sequence be the same as the replaced
540e4b17023SJohn Marino    statement and using new SSA names for stores in between.  */
541e4b17023SJohn Marino 
542e4b17023SJohn Marino void
gimplify_and_update_call_from_tree(gimple_stmt_iterator * si_p,tree expr)543e4b17023SJohn Marino gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
544e4b17023SJohn Marino {
545e4b17023SJohn Marino   tree lhs;
546e4b17023SJohn Marino   gimple stmt, new_stmt;
547e4b17023SJohn Marino   gimple_stmt_iterator i;
548e4b17023SJohn Marino   gimple_seq stmts = gimple_seq_alloc();
549e4b17023SJohn Marino   struct gimplify_ctx gctx;
550e4b17023SJohn Marino   gimple last;
551e4b17023SJohn Marino   gimple laststore;
552e4b17023SJohn Marino   tree reaching_vuse;
553e4b17023SJohn Marino 
554e4b17023SJohn Marino   stmt = gsi_stmt (*si_p);
555e4b17023SJohn Marino 
556e4b17023SJohn Marino   gcc_assert (is_gimple_call (stmt));
557e4b17023SJohn Marino 
558e4b17023SJohn Marino   push_gimplify_context (&gctx);
559e4b17023SJohn Marino   gctx.into_ssa = gimple_in_ssa_p (cfun);
560e4b17023SJohn Marino 
561e4b17023SJohn Marino   lhs = gimple_call_lhs (stmt);
562e4b17023SJohn Marino   if (lhs == NULL_TREE)
563e4b17023SJohn Marino     {
564e4b17023SJohn Marino       gimplify_and_add (expr, &stmts);
565e4b17023SJohn Marino       /* We can end up with folding a memcpy of an empty class assignment
566e4b17023SJohn Marino 	 which gets optimized away by C++ gimplification.  */
567e4b17023SJohn Marino       if (gimple_seq_empty_p (stmts))
568e4b17023SJohn Marino 	{
569e4b17023SJohn Marino 	  pop_gimplify_context (NULL);
570e4b17023SJohn Marino 	  if (gimple_in_ssa_p (cfun))
571e4b17023SJohn Marino 	    {
572e4b17023SJohn Marino 	      unlink_stmt_vdef (stmt);
573e4b17023SJohn Marino 	      release_defs (stmt);
574e4b17023SJohn Marino 	    }
575*5ce9237cSJohn Marino 	  gsi_replace (si_p, gimple_build_nop (), true);
576e4b17023SJohn Marino 	  return;
577e4b17023SJohn Marino 	}
578e4b17023SJohn Marino     }
579e4b17023SJohn Marino   else
580e4b17023SJohn Marino     {
581e4b17023SJohn Marino       tree tmp = get_initialized_tmp_var (expr, &stmts, NULL);
582e4b17023SJohn Marino       new_stmt = gimple_build_assign (lhs, tmp);
583e4b17023SJohn Marino       i = gsi_last (stmts);
584e4b17023SJohn Marino       gsi_insert_after_without_update (&i, new_stmt,
585e4b17023SJohn Marino 				       GSI_CONTINUE_LINKING);
586e4b17023SJohn Marino     }
587e4b17023SJohn Marino 
588e4b17023SJohn Marino   pop_gimplify_context (NULL);
589e4b17023SJohn Marino 
590e4b17023SJohn Marino   if (gimple_has_location (stmt))
591e4b17023SJohn Marino     annotate_all_with_location (stmts, gimple_location (stmt));
592e4b17023SJohn Marino 
593e4b17023SJohn Marino   /* First iterate over the replacement statements backward, assigning
594e4b17023SJohn Marino      virtual operands to their defining statements.  */
595e4b17023SJohn Marino   laststore = NULL;
596e4b17023SJohn Marino   for (i = gsi_last (stmts); !gsi_end_p (i); gsi_prev (&i))
597e4b17023SJohn Marino     {
598e4b17023SJohn Marino       new_stmt = gsi_stmt (i);
599e4b17023SJohn Marino       if ((gimple_assign_single_p (new_stmt)
600e4b17023SJohn Marino 	   && !is_gimple_reg (gimple_assign_lhs (new_stmt)))
601e4b17023SJohn Marino 	  || (is_gimple_call (new_stmt)
602e4b17023SJohn Marino 	      && (gimple_call_flags (new_stmt)
603e4b17023SJohn Marino 		  & (ECF_NOVOPS | ECF_PURE | ECF_CONST | ECF_NORETURN)) == 0))
604e4b17023SJohn Marino 	{
605e4b17023SJohn Marino 	  tree vdef;
606e4b17023SJohn Marino 	  if (!laststore)
607e4b17023SJohn Marino 	    vdef = gimple_vdef (stmt);
608e4b17023SJohn Marino 	  else
609e4b17023SJohn Marino 	    vdef = make_ssa_name (gimple_vop (cfun), new_stmt);
610e4b17023SJohn Marino 	  gimple_set_vdef (new_stmt, vdef);
611e4b17023SJohn Marino 	  if (vdef && TREE_CODE (vdef) == SSA_NAME)
612e4b17023SJohn Marino 	    SSA_NAME_DEF_STMT (vdef) = new_stmt;
613e4b17023SJohn Marino 	  laststore = new_stmt;
614e4b17023SJohn Marino 	}
615e4b17023SJohn Marino     }
616e4b17023SJohn Marino 
617e4b17023SJohn Marino   /* Second iterate over the statements forward, assigning virtual
618e4b17023SJohn Marino      operands to their uses.  */
619e4b17023SJohn Marino   last = NULL;
620e4b17023SJohn Marino   reaching_vuse = gimple_vuse (stmt);
621e4b17023SJohn Marino   for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
622e4b17023SJohn Marino     {
623e4b17023SJohn Marino       /* Do not insert the last stmt in this loop but remember it
624e4b17023SJohn Marino          for replacing the original statement.  */
625e4b17023SJohn Marino       if (last)
626e4b17023SJohn Marino 	{
627e4b17023SJohn Marino 	  gsi_insert_before (si_p, last, GSI_NEW_STMT);
628e4b17023SJohn Marino 	  gsi_next (si_p);
629e4b17023SJohn Marino 	}
630e4b17023SJohn Marino       new_stmt = gsi_stmt (i);
631e4b17023SJohn Marino       /* The replacement can expose previously unreferenced variables.  */
632e4b17023SJohn Marino       if (gimple_in_ssa_p (cfun))
633e4b17023SJohn Marino 	find_new_referenced_vars (new_stmt);
634e4b17023SJohn Marino       /* If the new statement possibly has a VUSE, update it with exact SSA
635e4b17023SJohn Marino 	 name we know will reach this one.  */
636e4b17023SJohn Marino       if (gimple_has_mem_ops (new_stmt))
637e4b17023SJohn Marino 	gimple_set_vuse (new_stmt, reaching_vuse);
638e4b17023SJohn Marino       gimple_set_modified (new_stmt, true);
639e4b17023SJohn Marino       if (gimple_vdef (new_stmt))
640e4b17023SJohn Marino 	reaching_vuse = gimple_vdef (new_stmt);
641e4b17023SJohn Marino       last = new_stmt;
642e4b17023SJohn Marino     }
643e4b17023SJohn Marino 
644e4b17023SJohn Marino   /* If the new sequence does not do a store release the virtual
645e4b17023SJohn Marino      definition of the original statement.  */
646e4b17023SJohn Marino   if (reaching_vuse
647e4b17023SJohn Marino       && reaching_vuse == gimple_vuse (stmt))
648e4b17023SJohn Marino     {
649e4b17023SJohn Marino       tree vdef = gimple_vdef (stmt);
650e4b17023SJohn Marino       if (vdef
651e4b17023SJohn Marino 	  && TREE_CODE (vdef) == SSA_NAME)
652e4b17023SJohn Marino 	{
653e4b17023SJohn Marino 	  unlink_stmt_vdef (stmt);
654e4b17023SJohn Marino 	  release_ssa_name (vdef);
655e4b17023SJohn Marino 	}
656e4b17023SJohn Marino     }
657e4b17023SJohn Marino 
658e4b17023SJohn Marino   /* Finally replace rhe original statement with the last.  */
659e4b17023SJohn Marino   gsi_replace (si_p, last, false);
660e4b17023SJohn Marino }
661e4b17023SJohn Marino 
662e4b17023SJohn Marino /* Return the string length, maximum string length or maximum value of
663e4b17023SJohn Marino    ARG in LENGTH.
664e4b17023SJohn Marino    If ARG is an SSA name variable, follow its use-def chains.  If LENGTH
665e4b17023SJohn Marino    is not NULL and, for TYPE == 0, its value is not equal to the length
666e4b17023SJohn Marino    we determine or if we are unable to determine the length or value,
667e4b17023SJohn Marino    return false.  VISITED is a bitmap of visited variables.
668e4b17023SJohn Marino    TYPE is 0 if string length should be returned, 1 for maximum string
669e4b17023SJohn Marino    length and 2 for maximum value ARG can have.  */
670e4b17023SJohn Marino 
671e4b17023SJohn Marino static bool
get_maxval_strlen(tree arg,tree * length,bitmap visited,int type)672e4b17023SJohn Marino get_maxval_strlen (tree arg, tree *length, bitmap visited, int type)
673e4b17023SJohn Marino {
674e4b17023SJohn Marino   tree var, val;
675e4b17023SJohn Marino   gimple def_stmt;
676e4b17023SJohn Marino 
677e4b17023SJohn Marino   if (TREE_CODE (arg) != SSA_NAME)
678e4b17023SJohn Marino     {
679e4b17023SJohn Marino       /* We can end up with &(*iftmp_1)[0] here as well, so handle it.  */
680e4b17023SJohn Marino       if (TREE_CODE (arg) == ADDR_EXPR
681e4b17023SJohn Marino 	  && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
682e4b17023SJohn Marino 	  && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg, 0), 1)))
683e4b17023SJohn Marino 	{
684e4b17023SJohn Marino 	  tree aop0 = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
685e4b17023SJohn Marino 	  if (TREE_CODE (aop0) == INDIRECT_REF
686e4b17023SJohn Marino 	      && TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
687e4b17023SJohn Marino 	    return get_maxval_strlen (TREE_OPERAND (aop0, 0),
688e4b17023SJohn Marino 				      length, visited, type);
689e4b17023SJohn Marino 	}
690e4b17023SJohn Marino 
691e4b17023SJohn Marino       if (type == 2)
692e4b17023SJohn Marino 	{
693e4b17023SJohn Marino 	  val = arg;
694e4b17023SJohn Marino 	  if (TREE_CODE (val) != INTEGER_CST
695e4b17023SJohn Marino 	      || tree_int_cst_sgn (val) < 0)
696e4b17023SJohn Marino 	    return false;
697e4b17023SJohn Marino 	}
698e4b17023SJohn Marino       else
699e4b17023SJohn Marino 	val = c_strlen (arg, 1);
700e4b17023SJohn Marino       if (!val)
701e4b17023SJohn Marino 	return false;
702e4b17023SJohn Marino 
703e4b17023SJohn Marino       if (*length)
704e4b17023SJohn Marino 	{
705e4b17023SJohn Marino 	  if (type > 0)
706e4b17023SJohn Marino 	    {
707e4b17023SJohn Marino 	      if (TREE_CODE (*length) != INTEGER_CST
708e4b17023SJohn Marino 		  || TREE_CODE (val) != INTEGER_CST)
709e4b17023SJohn Marino 		return false;
710e4b17023SJohn Marino 
711e4b17023SJohn Marino 	      if (tree_int_cst_lt (*length, val))
712e4b17023SJohn Marino 		*length = val;
713e4b17023SJohn Marino 	      return true;
714e4b17023SJohn Marino 	    }
715e4b17023SJohn Marino 	  else if (simple_cst_equal (val, *length) != 1)
716e4b17023SJohn Marino 	    return false;
717e4b17023SJohn Marino 	}
718e4b17023SJohn Marino 
719e4b17023SJohn Marino       *length = val;
720e4b17023SJohn Marino       return true;
721e4b17023SJohn Marino     }
722e4b17023SJohn Marino 
723e4b17023SJohn Marino   /* If we were already here, break the infinite cycle.  */
724e4b17023SJohn Marino   if (!bitmap_set_bit (visited, SSA_NAME_VERSION (arg)))
725e4b17023SJohn Marino     return true;
726e4b17023SJohn Marino 
727e4b17023SJohn Marino   var = arg;
728e4b17023SJohn Marino   def_stmt = SSA_NAME_DEF_STMT (var);
729e4b17023SJohn Marino 
730e4b17023SJohn Marino   switch (gimple_code (def_stmt))
731e4b17023SJohn Marino     {
732e4b17023SJohn Marino       case GIMPLE_ASSIGN:
733e4b17023SJohn Marino         /* The RHS of the statement defining VAR must either have a
734e4b17023SJohn Marino            constant length or come from another SSA_NAME with a constant
735e4b17023SJohn Marino            length.  */
736e4b17023SJohn Marino         if (gimple_assign_single_p (def_stmt)
737e4b17023SJohn Marino             || gimple_assign_unary_nop_p (def_stmt))
738e4b17023SJohn Marino           {
739e4b17023SJohn Marino             tree rhs = gimple_assign_rhs1 (def_stmt);
740e4b17023SJohn Marino             return get_maxval_strlen (rhs, length, visited, type);
741e4b17023SJohn Marino           }
742e4b17023SJohn Marino 	else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
743e4b17023SJohn Marino 	  {
744e4b17023SJohn Marino 	    tree op2 = gimple_assign_rhs2 (def_stmt);
745e4b17023SJohn Marino 	    tree op3 = gimple_assign_rhs3 (def_stmt);
746e4b17023SJohn Marino 	    return get_maxval_strlen (op2, length, visited, type)
747e4b17023SJohn Marino 		   && get_maxval_strlen (op3, length, visited, type);
748e4b17023SJohn Marino           }
749e4b17023SJohn Marino         return false;
750e4b17023SJohn Marino 
751e4b17023SJohn Marino       case GIMPLE_PHI:
752e4b17023SJohn Marino 	{
753e4b17023SJohn Marino 	  /* All the arguments of the PHI node must have the same constant
754e4b17023SJohn Marino 	     length.  */
755e4b17023SJohn Marino 	  unsigned i;
756e4b17023SJohn Marino 
757e4b17023SJohn Marino 	  for (i = 0; i < gimple_phi_num_args (def_stmt); i++)
758e4b17023SJohn Marino           {
759e4b17023SJohn Marino             tree arg = gimple_phi_arg (def_stmt, i)->def;
760e4b17023SJohn Marino 
761e4b17023SJohn Marino             /* If this PHI has itself as an argument, we cannot
762e4b17023SJohn Marino                determine the string length of this argument.  However,
763e4b17023SJohn Marino                if we can find a constant string length for the other
764e4b17023SJohn Marino                PHI args then we can still be sure that this is a
765e4b17023SJohn Marino                constant string length.  So be optimistic and just
766e4b17023SJohn Marino                continue with the next argument.  */
767e4b17023SJohn Marino             if (arg == gimple_phi_result (def_stmt))
768e4b17023SJohn Marino               continue;
769e4b17023SJohn Marino 
770e4b17023SJohn Marino             if (!get_maxval_strlen (arg, length, visited, type))
771e4b17023SJohn Marino               return false;
772e4b17023SJohn Marino           }
773e4b17023SJohn Marino         }
774e4b17023SJohn Marino         return true;
775e4b17023SJohn Marino 
776e4b17023SJohn Marino       default:
777e4b17023SJohn Marino         return false;
778e4b17023SJohn Marino     }
779e4b17023SJohn Marino }
780e4b17023SJohn Marino 
781e4b17023SJohn Marino 
782e4b17023SJohn Marino /* Fold builtin call in statement STMT.  Returns a simplified tree.
783e4b17023SJohn Marino    We may return a non-constant expression, including another call
784e4b17023SJohn Marino    to a different function and with different arguments, e.g.,
785e4b17023SJohn Marino    substituting memcpy for strcpy when the string length is known.
786e4b17023SJohn Marino    Note that some builtins expand into inline code that may not
787e4b17023SJohn Marino    be valid in GIMPLE.  Callers must take care.  */
788e4b17023SJohn Marino 
789e4b17023SJohn Marino tree
gimple_fold_builtin(gimple stmt)790e4b17023SJohn Marino gimple_fold_builtin (gimple stmt)
791e4b17023SJohn Marino {
792e4b17023SJohn Marino   tree result, val[3];
793e4b17023SJohn Marino   tree callee, a;
794e4b17023SJohn Marino   int arg_idx, type;
795e4b17023SJohn Marino   bitmap visited;
796e4b17023SJohn Marino   bool ignore;
797e4b17023SJohn Marino   int nargs;
798e4b17023SJohn Marino   location_t loc = gimple_location (stmt);
799e4b17023SJohn Marino 
800e4b17023SJohn Marino   gcc_assert (is_gimple_call (stmt));
801e4b17023SJohn Marino 
802e4b17023SJohn Marino   ignore = (gimple_call_lhs (stmt) == NULL);
803e4b17023SJohn Marino 
804e4b17023SJohn Marino   /* First try the generic builtin folder.  If that succeeds, return the
805e4b17023SJohn Marino      result directly.  */
806e4b17023SJohn Marino   result = fold_call_stmt (stmt, ignore);
807e4b17023SJohn Marino   if (result)
808e4b17023SJohn Marino     {
809e4b17023SJohn Marino       if (ignore)
810e4b17023SJohn Marino 	STRIP_NOPS (result);
811e4b17023SJohn Marino       return result;
812e4b17023SJohn Marino     }
813e4b17023SJohn Marino 
814e4b17023SJohn Marino   /* Ignore MD builtins.  */
815e4b17023SJohn Marino   callee = gimple_call_fndecl (stmt);
816e4b17023SJohn Marino   if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
817e4b17023SJohn Marino     return NULL_TREE;
818e4b17023SJohn Marino 
819e4b17023SJohn Marino   /* Give up for always_inline inline builtins until they are
820e4b17023SJohn Marino      inlined.  */
821e4b17023SJohn Marino   if (avoid_folding_inline_builtin (callee))
822e4b17023SJohn Marino     return NULL_TREE;
823e4b17023SJohn Marino 
824e4b17023SJohn Marino   /* If the builtin could not be folded, and it has no argument list,
825e4b17023SJohn Marino      we're done.  */
826e4b17023SJohn Marino   nargs = gimple_call_num_args (stmt);
827e4b17023SJohn Marino   if (nargs == 0)
828e4b17023SJohn Marino     return NULL_TREE;
829e4b17023SJohn Marino 
830e4b17023SJohn Marino   /* Limit the work only for builtins we know how to simplify.  */
831e4b17023SJohn Marino   switch (DECL_FUNCTION_CODE (callee))
832e4b17023SJohn Marino     {
833e4b17023SJohn Marino     case BUILT_IN_STRLEN:
834e4b17023SJohn Marino     case BUILT_IN_FPUTS:
835e4b17023SJohn Marino     case BUILT_IN_FPUTS_UNLOCKED:
836e4b17023SJohn Marino       arg_idx = 0;
837e4b17023SJohn Marino       type = 0;
838e4b17023SJohn Marino       break;
839e4b17023SJohn Marino     case BUILT_IN_STRCPY:
840e4b17023SJohn Marino     case BUILT_IN_STRNCPY:
841e4b17023SJohn Marino       arg_idx = 1;
842e4b17023SJohn Marino       type = 0;
843e4b17023SJohn Marino       break;
844e4b17023SJohn Marino     case BUILT_IN_MEMCPY_CHK:
845e4b17023SJohn Marino     case BUILT_IN_MEMPCPY_CHK:
846e4b17023SJohn Marino     case BUILT_IN_MEMMOVE_CHK:
847e4b17023SJohn Marino     case BUILT_IN_MEMSET_CHK:
848e4b17023SJohn Marino     case BUILT_IN_STRNCPY_CHK:
849e4b17023SJohn Marino     case BUILT_IN_STPNCPY_CHK:
850e4b17023SJohn Marino       arg_idx = 2;
851e4b17023SJohn Marino       type = 2;
852e4b17023SJohn Marino       break;
853e4b17023SJohn Marino     case BUILT_IN_STRCPY_CHK:
854e4b17023SJohn Marino     case BUILT_IN_STPCPY_CHK:
855e4b17023SJohn Marino       arg_idx = 1;
856e4b17023SJohn Marino       type = 1;
857e4b17023SJohn Marino       break;
858e4b17023SJohn Marino     case BUILT_IN_SNPRINTF_CHK:
859e4b17023SJohn Marino     case BUILT_IN_VSNPRINTF_CHK:
860e4b17023SJohn Marino       arg_idx = 1;
861e4b17023SJohn Marino       type = 2;
862e4b17023SJohn Marino       break;
863e4b17023SJohn Marino     default:
864e4b17023SJohn Marino       return NULL_TREE;
865e4b17023SJohn Marino     }
866e4b17023SJohn Marino 
867e4b17023SJohn Marino   if (arg_idx >= nargs)
868e4b17023SJohn Marino     return NULL_TREE;
869e4b17023SJohn Marino 
870e4b17023SJohn Marino   /* Try to use the dataflow information gathered by the CCP process.  */
871e4b17023SJohn Marino   visited = BITMAP_ALLOC (NULL);
872e4b17023SJohn Marino   bitmap_clear (visited);
873e4b17023SJohn Marino 
874e4b17023SJohn Marino   memset (val, 0, sizeof (val));
875e4b17023SJohn Marino   a = gimple_call_arg (stmt, arg_idx);
876e4b17023SJohn Marino   if (!get_maxval_strlen (a, &val[arg_idx], visited, type))
877e4b17023SJohn Marino     val[arg_idx] = NULL_TREE;
878e4b17023SJohn Marino 
879e4b17023SJohn Marino   BITMAP_FREE (visited);
880e4b17023SJohn Marino 
881e4b17023SJohn Marino   result = NULL_TREE;
882e4b17023SJohn Marino   switch (DECL_FUNCTION_CODE (callee))
883e4b17023SJohn Marino     {
884e4b17023SJohn Marino     case BUILT_IN_STRLEN:
885e4b17023SJohn Marino       if (val[0] && nargs == 1)
886e4b17023SJohn Marino 	{
887e4b17023SJohn Marino 	  tree new_val =
888e4b17023SJohn Marino               fold_convert (TREE_TYPE (gimple_call_lhs (stmt)), val[0]);
889e4b17023SJohn Marino 
890e4b17023SJohn Marino 	  /* If the result is not a valid gimple value, or not a cast
891e4b17023SJohn Marino 	     of a valid gimple value, then we cannot use the result.  */
892e4b17023SJohn Marino 	  if (is_gimple_val (new_val)
893e4b17023SJohn Marino 	      || (CONVERT_EXPR_P (new_val)
894e4b17023SJohn Marino 		  && is_gimple_val (TREE_OPERAND (new_val, 0))))
895e4b17023SJohn Marino 	    return new_val;
896e4b17023SJohn Marino 	}
897e4b17023SJohn Marino       break;
898e4b17023SJohn Marino 
899e4b17023SJohn Marino     case BUILT_IN_STRCPY:
900e4b17023SJohn Marino       if (val[1] && is_gimple_val (val[1]) && nargs == 2)
901e4b17023SJohn Marino 	result = fold_builtin_strcpy (loc, callee,
902e4b17023SJohn Marino                                       gimple_call_arg (stmt, 0),
903e4b17023SJohn Marino                                       gimple_call_arg (stmt, 1),
904e4b17023SJohn Marino 				      val[1]);
905e4b17023SJohn Marino       break;
906e4b17023SJohn Marino 
907e4b17023SJohn Marino     case BUILT_IN_STRNCPY:
908e4b17023SJohn Marino       if (val[1] && is_gimple_val (val[1]) && nargs == 3)
909e4b17023SJohn Marino 	result = fold_builtin_strncpy (loc, callee,
910e4b17023SJohn Marino                                        gimple_call_arg (stmt, 0),
911e4b17023SJohn Marino                                        gimple_call_arg (stmt, 1),
912e4b17023SJohn Marino                                        gimple_call_arg (stmt, 2),
913e4b17023SJohn Marino 				       val[1]);
914e4b17023SJohn Marino       break;
915e4b17023SJohn Marino 
916e4b17023SJohn Marino     case BUILT_IN_FPUTS:
917e4b17023SJohn Marino       if (nargs == 2)
918e4b17023SJohn Marino 	result = fold_builtin_fputs (loc, gimple_call_arg (stmt, 0),
919e4b17023SJohn Marino 				     gimple_call_arg (stmt, 1),
920e4b17023SJohn Marino 				     ignore, false, val[0]);
921e4b17023SJohn Marino       break;
922e4b17023SJohn Marino 
923e4b17023SJohn Marino     case BUILT_IN_FPUTS_UNLOCKED:
924e4b17023SJohn Marino       if (nargs == 2)
925e4b17023SJohn Marino 	result = fold_builtin_fputs (loc, gimple_call_arg (stmt, 0),
926e4b17023SJohn Marino 				     gimple_call_arg (stmt, 1),
927e4b17023SJohn Marino 				     ignore, true, val[0]);
928e4b17023SJohn Marino       break;
929e4b17023SJohn Marino 
930e4b17023SJohn Marino     case BUILT_IN_MEMCPY_CHK:
931e4b17023SJohn Marino     case BUILT_IN_MEMPCPY_CHK:
932e4b17023SJohn Marino     case BUILT_IN_MEMMOVE_CHK:
933e4b17023SJohn Marino     case BUILT_IN_MEMSET_CHK:
934e4b17023SJohn Marino       if (val[2] && is_gimple_val (val[2]) && nargs == 4)
935e4b17023SJohn Marino 	result = fold_builtin_memory_chk (loc, callee,
936e4b17023SJohn Marino                                           gimple_call_arg (stmt, 0),
937e4b17023SJohn Marino                                           gimple_call_arg (stmt, 1),
938e4b17023SJohn Marino                                           gimple_call_arg (stmt, 2),
939e4b17023SJohn Marino                                           gimple_call_arg (stmt, 3),
940e4b17023SJohn Marino 					  val[2], ignore,
941e4b17023SJohn Marino 					  DECL_FUNCTION_CODE (callee));
942e4b17023SJohn Marino       break;
943e4b17023SJohn Marino 
944e4b17023SJohn Marino     case BUILT_IN_STRCPY_CHK:
945e4b17023SJohn Marino     case BUILT_IN_STPCPY_CHK:
946e4b17023SJohn Marino       if (val[1] && is_gimple_val (val[1]) && nargs == 3)
947e4b17023SJohn Marino 	result = fold_builtin_stxcpy_chk (loc, callee,
948e4b17023SJohn Marino                                           gimple_call_arg (stmt, 0),
949e4b17023SJohn Marino                                           gimple_call_arg (stmt, 1),
950e4b17023SJohn Marino                                           gimple_call_arg (stmt, 2),
951e4b17023SJohn Marino 					  val[1], ignore,
952e4b17023SJohn Marino 					  DECL_FUNCTION_CODE (callee));
953e4b17023SJohn Marino       break;
954e4b17023SJohn Marino 
955e4b17023SJohn Marino     case BUILT_IN_STRNCPY_CHK:
956e4b17023SJohn Marino     case BUILT_IN_STPNCPY_CHK:
957e4b17023SJohn Marino       if (val[2] && is_gimple_val (val[2]) && nargs == 4)
958e4b17023SJohn Marino 	result = fold_builtin_stxncpy_chk (loc, gimple_call_arg (stmt, 0),
959e4b17023SJohn Marino                                            gimple_call_arg (stmt, 1),
960e4b17023SJohn Marino                                            gimple_call_arg (stmt, 2),
961e4b17023SJohn Marino                                            gimple_call_arg (stmt, 3),
962e4b17023SJohn Marino 					   val[2], ignore,
963e4b17023SJohn Marino 					   DECL_FUNCTION_CODE (callee));
964e4b17023SJohn Marino       break;
965e4b17023SJohn Marino 
966e4b17023SJohn Marino     case BUILT_IN_SNPRINTF_CHK:
967e4b17023SJohn Marino     case BUILT_IN_VSNPRINTF_CHK:
968e4b17023SJohn Marino       if (val[1] && is_gimple_val (val[1]))
969e4b17023SJohn Marino 	result = gimple_fold_builtin_snprintf_chk (stmt, val[1],
970e4b17023SJohn Marino                                                    DECL_FUNCTION_CODE (callee));
971e4b17023SJohn Marino       break;
972e4b17023SJohn Marino 
973e4b17023SJohn Marino     default:
974e4b17023SJohn Marino       gcc_unreachable ();
975e4b17023SJohn Marino     }
976e4b17023SJohn Marino 
977e4b17023SJohn Marino   if (result && ignore)
978e4b17023SJohn Marino     result = fold_ignored_result (result);
979e4b17023SJohn Marino   return result;
980e4b17023SJohn Marino }
981e4b17023SJohn Marino 
982e4b17023SJohn Marino /* Generate code adjusting the first parameter of a call statement determined
983e4b17023SJohn Marino    by GSI by DELTA.  */
984e4b17023SJohn Marino 
985e4b17023SJohn Marino void
gimple_adjust_this_by_delta(gimple_stmt_iterator * gsi,tree delta)986e4b17023SJohn Marino gimple_adjust_this_by_delta (gimple_stmt_iterator *gsi, tree delta)
987e4b17023SJohn Marino {
988e4b17023SJohn Marino   gimple call_stmt = gsi_stmt (*gsi);
989e4b17023SJohn Marino   tree parm, tmp;
990e4b17023SJohn Marino   gimple new_stmt;
991e4b17023SJohn Marino 
992e4b17023SJohn Marino   delta = convert_to_ptrofftype (delta);
993e4b17023SJohn Marino   gcc_assert (gimple_call_num_args (call_stmt) >= 1);
994e4b17023SJohn Marino   parm = gimple_call_arg (call_stmt, 0);
995e4b17023SJohn Marino   gcc_assert (POINTER_TYPE_P (TREE_TYPE (parm)));
996e4b17023SJohn Marino   tmp = create_tmp_var (TREE_TYPE (parm), NULL);
997e4b17023SJohn Marino   add_referenced_var (tmp);
998e4b17023SJohn Marino 
999e4b17023SJohn Marino   tmp = make_ssa_name (tmp, NULL);
1000e4b17023SJohn Marino   new_stmt = gimple_build_assign_with_ops (POINTER_PLUS_EXPR, tmp, parm, delta);
1001e4b17023SJohn Marino   SSA_NAME_DEF_STMT (tmp) = new_stmt;
1002e4b17023SJohn Marino   gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
1003e4b17023SJohn Marino   gimple_call_set_arg (call_stmt, 0, tmp);
1004e4b17023SJohn Marino }
1005e4b17023SJohn Marino 
1006e4b17023SJohn Marino /* Return a binfo to be used for devirtualization of calls based on an object
1007e4b17023SJohn Marino    represented by a declaration (i.e. a global or automatically allocated one)
1008e4b17023SJohn Marino    or NULL if it cannot be found or is not safe.  CST is expected to be an
1009e4b17023SJohn Marino    ADDR_EXPR of such object or the function will return NULL.  Currently it is
1010e4b17023SJohn Marino    safe to use such binfo only if it has no base binfo (i.e. no ancestors).  */
1011e4b17023SJohn Marino 
1012e4b17023SJohn Marino tree
gimple_extract_devirt_binfo_from_cst(tree cst)1013e4b17023SJohn Marino gimple_extract_devirt_binfo_from_cst (tree cst)
1014e4b17023SJohn Marino {
1015e4b17023SJohn Marino   HOST_WIDE_INT offset, size, max_size;
1016e4b17023SJohn Marino   tree base, type, expected_type, binfo;
1017e4b17023SJohn Marino   bool last_artificial = false;
1018e4b17023SJohn Marino 
1019e4b17023SJohn Marino   if (!flag_devirtualize
1020e4b17023SJohn Marino       || TREE_CODE (cst) != ADDR_EXPR
1021e4b17023SJohn Marino       || TREE_CODE (TREE_TYPE (TREE_TYPE (cst))) != RECORD_TYPE)
1022e4b17023SJohn Marino     return NULL_TREE;
1023e4b17023SJohn Marino 
1024e4b17023SJohn Marino   cst = TREE_OPERAND (cst, 0);
1025e4b17023SJohn Marino   expected_type = TREE_TYPE (cst);
1026e4b17023SJohn Marino   base = get_ref_base_and_extent (cst, &offset, &size, &max_size);
1027e4b17023SJohn Marino   type = TREE_TYPE (base);
1028e4b17023SJohn Marino   if (!DECL_P (base)
1029e4b17023SJohn Marino       || max_size == -1
1030e4b17023SJohn Marino       || max_size != size
1031e4b17023SJohn Marino       || TREE_CODE (type) != RECORD_TYPE)
1032e4b17023SJohn Marino     return NULL_TREE;
1033e4b17023SJohn Marino 
1034e4b17023SJohn Marino   /* Find the sub-object the constant actually refers to and mark whether it is
1035e4b17023SJohn Marino      an artificial one (as opposed to a user-defined one).  */
1036e4b17023SJohn Marino   while (true)
1037e4b17023SJohn Marino     {
1038e4b17023SJohn Marino       HOST_WIDE_INT pos, size;
1039e4b17023SJohn Marino       tree fld;
1040e4b17023SJohn Marino 
1041e4b17023SJohn Marino       if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type))
1042e4b17023SJohn Marino 	break;
1043e4b17023SJohn Marino       if (offset < 0)
1044e4b17023SJohn Marino 	return NULL_TREE;
1045e4b17023SJohn Marino 
1046e4b17023SJohn Marino       for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
1047e4b17023SJohn Marino 	{
1048e4b17023SJohn Marino 	  if (TREE_CODE (fld) != FIELD_DECL)
1049e4b17023SJohn Marino 	    continue;
1050e4b17023SJohn Marino 
1051e4b17023SJohn Marino 	  pos = int_bit_position (fld);
1052e4b17023SJohn Marino 	  size = tree_low_cst (DECL_SIZE (fld), 1);
1053e4b17023SJohn Marino 	  if (pos <= offset && (pos + size) > offset)
1054e4b17023SJohn Marino 	    break;
1055e4b17023SJohn Marino 	}
1056e4b17023SJohn Marino       if (!fld || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE)
1057e4b17023SJohn Marino 	return NULL_TREE;
1058e4b17023SJohn Marino 
1059e4b17023SJohn Marino       last_artificial = DECL_ARTIFICIAL (fld);
1060e4b17023SJohn Marino       type = TREE_TYPE (fld);
1061e4b17023SJohn Marino       offset -= pos;
1062e4b17023SJohn Marino     }
1063e4b17023SJohn Marino   /* Artifical sub-objects are ancestors, we do not want to use them for
1064e4b17023SJohn Marino      devirtualization, at least not here.  */
1065e4b17023SJohn Marino   if (last_artificial)
1066e4b17023SJohn Marino     return NULL_TREE;
1067e4b17023SJohn Marino   binfo = TYPE_BINFO (type);
1068e4b17023SJohn Marino   if (!binfo || BINFO_N_BASE_BINFOS (binfo) > 0)
1069e4b17023SJohn Marino     return NULL_TREE;
1070e4b17023SJohn Marino   else
1071e4b17023SJohn Marino     return binfo;
1072e4b17023SJohn Marino }
1073e4b17023SJohn Marino 
1074e4b17023SJohn Marino /* Attempt to fold a call statement referenced by the statement iterator GSI.
1075e4b17023SJohn Marino    The statement may be replaced by another statement, e.g., if the call
1076e4b17023SJohn Marino    simplifies to a constant value. Return true if any changes were made.
1077e4b17023SJohn Marino    It is assumed that the operands have been previously folded.  */
1078e4b17023SJohn Marino 
1079e4b17023SJohn Marino static bool
gimple_fold_call(gimple_stmt_iterator * gsi,bool inplace)1080e4b17023SJohn Marino gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
1081e4b17023SJohn Marino {
1082e4b17023SJohn Marino   gimple stmt = gsi_stmt (*gsi);
1083e4b17023SJohn Marino   tree callee;
1084e4b17023SJohn Marino   bool changed = false;
1085e4b17023SJohn Marino   unsigned i;
1086e4b17023SJohn Marino 
1087e4b17023SJohn Marino   /* Fold *& in call arguments.  */
1088e4b17023SJohn Marino   for (i = 0; i < gimple_call_num_args (stmt); ++i)
1089e4b17023SJohn Marino     if (REFERENCE_CLASS_P (gimple_call_arg (stmt, i)))
1090e4b17023SJohn Marino       {
1091e4b17023SJohn Marino 	tree tmp = maybe_fold_reference (gimple_call_arg (stmt, i), false);
1092e4b17023SJohn Marino 	if (tmp)
1093e4b17023SJohn Marino 	  {
1094e4b17023SJohn Marino 	    gimple_call_set_arg (stmt, i, tmp);
1095e4b17023SJohn Marino 	    changed = true;
1096e4b17023SJohn Marino 	  }
1097e4b17023SJohn Marino       }
1098e4b17023SJohn Marino 
1099e4b17023SJohn Marino   /* Check for virtual calls that became direct calls.  */
1100e4b17023SJohn Marino   callee = gimple_call_fn (stmt);
1101e4b17023SJohn Marino   if (callee && TREE_CODE (callee) == OBJ_TYPE_REF)
1102e4b17023SJohn Marino     {
1103e4b17023SJohn Marino       if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
1104e4b17023SJohn Marino 	{
1105e4b17023SJohn Marino 	  gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee));
1106e4b17023SJohn Marino 	  changed = true;
1107e4b17023SJohn Marino 	}
1108e4b17023SJohn Marino       else
1109e4b17023SJohn Marino 	{
1110e4b17023SJohn Marino 	  tree obj = OBJ_TYPE_REF_OBJECT (callee);
1111e4b17023SJohn Marino 	  tree binfo = gimple_extract_devirt_binfo_from_cst (obj);
1112e4b17023SJohn Marino 	  if (binfo)
1113e4b17023SJohn Marino 	    {
1114e4b17023SJohn Marino 	      HOST_WIDE_INT token
1115e4b17023SJohn Marino 		= TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
1116e4b17023SJohn Marino 	      tree fndecl = gimple_get_virt_method_for_binfo (token, binfo);
1117e4b17023SJohn Marino 	      if (fndecl)
1118e4b17023SJohn Marino 		{
1119e4b17023SJohn Marino 		  gimple_call_set_fndecl (stmt, fndecl);
1120e4b17023SJohn Marino 		  changed = true;
1121e4b17023SJohn Marino 		}
1122e4b17023SJohn Marino 	    }
1123e4b17023SJohn Marino 	}
1124e4b17023SJohn Marino     }
1125e4b17023SJohn Marino 
1126e4b17023SJohn Marino   if (inplace)
1127e4b17023SJohn Marino     return changed;
1128e4b17023SJohn Marino 
1129e4b17023SJohn Marino   /* Check for builtins that CCP can handle using information not
1130e4b17023SJohn Marino      available in the generic fold routines.  */
1131e4b17023SJohn Marino   callee = gimple_call_fndecl (stmt);
1132e4b17023SJohn Marino   if (callee && DECL_BUILT_IN (callee))
1133e4b17023SJohn Marino     {
1134e4b17023SJohn Marino       tree result = gimple_fold_builtin (stmt);
1135e4b17023SJohn Marino       if (result)
1136e4b17023SJohn Marino 	{
1137e4b17023SJohn Marino           if (!update_call_from_tree (gsi, result))
1138e4b17023SJohn Marino 	    gimplify_and_update_call_from_tree (gsi, result);
1139e4b17023SJohn Marino 	  changed = true;
1140e4b17023SJohn Marino 	}
1141e4b17023SJohn Marino     }
1142e4b17023SJohn Marino 
1143e4b17023SJohn Marino   return changed;
1144e4b17023SJohn Marino }
1145e4b17023SJohn Marino 
1146e4b17023SJohn Marino /* Worker for both fold_stmt and fold_stmt_inplace.  The INPLACE argument
1147e4b17023SJohn Marino    distinguishes both cases.  */
1148e4b17023SJohn Marino 
1149e4b17023SJohn Marino static bool
fold_stmt_1(gimple_stmt_iterator * gsi,bool inplace)1150e4b17023SJohn Marino fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
1151e4b17023SJohn Marino {
1152e4b17023SJohn Marino   bool changed = false;
1153e4b17023SJohn Marino   gimple stmt = gsi_stmt (*gsi);
1154e4b17023SJohn Marino   unsigned i;
1155e4b17023SJohn Marino   gimple_stmt_iterator gsinext = *gsi;
1156e4b17023SJohn Marino   gimple next_stmt;
1157e4b17023SJohn Marino 
1158e4b17023SJohn Marino   gsi_next (&gsinext);
1159e4b17023SJohn Marino   next_stmt = gsi_end_p (gsinext) ? NULL : gsi_stmt (gsinext);
1160e4b17023SJohn Marino 
1161e4b17023SJohn Marino   /* Fold the main computation performed by the statement.  */
1162e4b17023SJohn Marino   switch (gimple_code (stmt))
1163e4b17023SJohn Marino     {
1164e4b17023SJohn Marino     case GIMPLE_ASSIGN:
1165e4b17023SJohn Marino       {
1166e4b17023SJohn Marino 	unsigned old_num_ops = gimple_num_ops (stmt);
1167e4b17023SJohn Marino 	enum tree_code subcode = gimple_assign_rhs_code (stmt);
1168e4b17023SJohn Marino 	tree lhs = gimple_assign_lhs (stmt);
1169e4b17023SJohn Marino 	tree new_rhs;
1170e4b17023SJohn Marino 	/* First canonicalize operand order.  This avoids building new
1171e4b17023SJohn Marino 	   trees if this is the only thing fold would later do.  */
1172e4b17023SJohn Marino 	if ((commutative_tree_code (subcode)
1173e4b17023SJohn Marino 	     || commutative_ternary_tree_code (subcode))
1174e4b17023SJohn Marino 	    && tree_swap_operands_p (gimple_assign_rhs1 (stmt),
1175e4b17023SJohn Marino 				     gimple_assign_rhs2 (stmt), false))
1176e4b17023SJohn Marino 	  {
1177e4b17023SJohn Marino 	    tree tem = gimple_assign_rhs1 (stmt);
1178e4b17023SJohn Marino 	    gimple_assign_set_rhs1 (stmt, gimple_assign_rhs2 (stmt));
1179e4b17023SJohn Marino 	    gimple_assign_set_rhs2 (stmt, tem);
1180e4b17023SJohn Marino 	    changed = true;
1181e4b17023SJohn Marino 	  }
1182e4b17023SJohn Marino 	new_rhs = fold_gimple_assign (gsi);
1183e4b17023SJohn Marino 	if (new_rhs
1184e4b17023SJohn Marino 	    && !useless_type_conversion_p (TREE_TYPE (lhs),
1185e4b17023SJohn Marino 					   TREE_TYPE (new_rhs)))
1186e4b17023SJohn Marino 	  new_rhs = fold_convert (TREE_TYPE (lhs), new_rhs);
1187e4b17023SJohn Marino 	if (new_rhs
1188e4b17023SJohn Marino 	    && (!inplace
1189e4b17023SJohn Marino 		|| get_gimple_rhs_num_ops (TREE_CODE (new_rhs)) < old_num_ops))
1190e4b17023SJohn Marino 	  {
1191e4b17023SJohn Marino 	    gimple_assign_set_rhs_from_tree (gsi, new_rhs);
1192e4b17023SJohn Marino 	    changed = true;
1193e4b17023SJohn Marino 	  }
1194e4b17023SJohn Marino 	break;
1195e4b17023SJohn Marino       }
1196e4b17023SJohn Marino 
1197e4b17023SJohn Marino     case GIMPLE_COND:
1198e4b17023SJohn Marino       changed |= fold_gimple_cond (stmt);
1199e4b17023SJohn Marino       break;
1200e4b17023SJohn Marino 
1201e4b17023SJohn Marino     case GIMPLE_CALL:
1202e4b17023SJohn Marino       changed |= gimple_fold_call (gsi, inplace);
1203e4b17023SJohn Marino       break;
1204e4b17023SJohn Marino 
1205e4b17023SJohn Marino     case GIMPLE_ASM:
1206e4b17023SJohn Marino       /* Fold *& in asm operands.  */
1207e4b17023SJohn Marino       {
1208e4b17023SJohn Marino 	size_t noutputs;
1209e4b17023SJohn Marino 	const char **oconstraints;
1210e4b17023SJohn Marino 	const char *constraint;
1211e4b17023SJohn Marino 	bool allows_mem, allows_reg;
1212e4b17023SJohn Marino 
1213e4b17023SJohn Marino 	noutputs = gimple_asm_noutputs (stmt);
1214e4b17023SJohn Marino 	oconstraints = XALLOCAVEC (const char *, noutputs);
1215e4b17023SJohn Marino 
1216e4b17023SJohn Marino 	for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
1217e4b17023SJohn Marino 	  {
1218e4b17023SJohn Marino 	    tree link = gimple_asm_output_op (stmt, i);
1219e4b17023SJohn Marino 	    tree op = TREE_VALUE (link);
1220e4b17023SJohn Marino 	    oconstraints[i]
1221e4b17023SJohn Marino 	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
1222e4b17023SJohn Marino 	    if (REFERENCE_CLASS_P (op)
1223e4b17023SJohn Marino 		&& (op = maybe_fold_reference (op, true)) != NULL_TREE)
1224e4b17023SJohn Marino 	      {
1225e4b17023SJohn Marino 		TREE_VALUE (link) = op;
1226e4b17023SJohn Marino 		changed = true;
1227e4b17023SJohn Marino 	      }
1228e4b17023SJohn Marino 	  }
1229e4b17023SJohn Marino 	for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
1230e4b17023SJohn Marino 	  {
1231e4b17023SJohn Marino 	    tree link = gimple_asm_input_op (stmt, i);
1232e4b17023SJohn Marino 	    tree op = TREE_VALUE (link);
1233e4b17023SJohn Marino 	    constraint
1234e4b17023SJohn Marino 	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
1235e4b17023SJohn Marino 	    parse_input_constraint (&constraint, 0, 0, noutputs, 0,
1236e4b17023SJohn Marino 				    oconstraints, &allows_mem, &allows_reg);
1237e4b17023SJohn Marino 	    if (REFERENCE_CLASS_P (op)
1238e4b17023SJohn Marino 		&& (op = maybe_fold_reference (op, !allows_reg && allows_mem))
1239e4b17023SJohn Marino 		   != NULL_TREE)
1240e4b17023SJohn Marino 	      {
1241e4b17023SJohn Marino 		TREE_VALUE (link) = op;
1242e4b17023SJohn Marino 		changed = true;
1243e4b17023SJohn Marino 	      }
1244e4b17023SJohn Marino 	  }
1245e4b17023SJohn Marino       }
1246e4b17023SJohn Marino       break;
1247e4b17023SJohn Marino 
1248e4b17023SJohn Marino     case GIMPLE_DEBUG:
1249e4b17023SJohn Marino       if (gimple_debug_bind_p (stmt))
1250e4b17023SJohn Marino 	{
1251e4b17023SJohn Marino 	  tree val = gimple_debug_bind_get_value (stmt);
1252e4b17023SJohn Marino 	  if (val
1253e4b17023SJohn Marino 	      && REFERENCE_CLASS_P (val))
1254e4b17023SJohn Marino 	    {
1255e4b17023SJohn Marino 	      tree tem = maybe_fold_reference (val, false);
1256e4b17023SJohn Marino 	      if (tem)
1257e4b17023SJohn Marino 		{
1258e4b17023SJohn Marino 		  gimple_debug_bind_set_value (stmt, tem);
1259e4b17023SJohn Marino 		  changed = true;
1260e4b17023SJohn Marino 		}
1261e4b17023SJohn Marino 	    }
1262e4b17023SJohn Marino 	  else if (val
1263e4b17023SJohn Marino 		   && TREE_CODE (val) == ADDR_EXPR)
1264e4b17023SJohn Marino 	    {
1265e4b17023SJohn Marino 	      tree ref = TREE_OPERAND (val, 0);
1266e4b17023SJohn Marino 	      tree tem = maybe_fold_reference (ref, false);
1267e4b17023SJohn Marino 	      if (tem)
1268e4b17023SJohn Marino 		{
1269e4b17023SJohn Marino 		  tem = build_fold_addr_expr_with_type (tem, TREE_TYPE (val));
1270e4b17023SJohn Marino 		  gimple_debug_bind_set_value (stmt, tem);
1271e4b17023SJohn Marino 		  changed = true;
1272e4b17023SJohn Marino 		}
1273e4b17023SJohn Marino 	    }
1274e4b17023SJohn Marino 	}
1275e4b17023SJohn Marino       break;
1276e4b17023SJohn Marino 
1277e4b17023SJohn Marino     default:;
1278e4b17023SJohn Marino     }
1279e4b17023SJohn Marino 
1280e4b17023SJohn Marino   /* If stmt folds into nothing and it was the last stmt in a bb,
1281e4b17023SJohn Marino      don't call gsi_stmt.  */
1282e4b17023SJohn Marino   if (gsi_end_p (*gsi))
1283e4b17023SJohn Marino     {
1284e4b17023SJohn Marino       gcc_assert (next_stmt == NULL);
1285e4b17023SJohn Marino       return changed;
1286e4b17023SJohn Marino     }
1287e4b17023SJohn Marino 
1288e4b17023SJohn Marino   stmt = gsi_stmt (*gsi);
1289e4b17023SJohn Marino 
1290e4b17023SJohn Marino   /* Fold *& on the lhs.  Don't do this if stmt folded into nothing,
1291e4b17023SJohn Marino      as we'd changing the next stmt.  */
1292e4b17023SJohn Marino   if (gimple_has_lhs (stmt) && stmt != next_stmt)
1293e4b17023SJohn Marino     {
1294e4b17023SJohn Marino       tree lhs = gimple_get_lhs (stmt);
1295e4b17023SJohn Marino       if (lhs && REFERENCE_CLASS_P (lhs))
1296e4b17023SJohn Marino 	{
1297e4b17023SJohn Marino 	  tree new_lhs = maybe_fold_reference (lhs, true);
1298e4b17023SJohn Marino 	  if (new_lhs)
1299e4b17023SJohn Marino 	    {
1300e4b17023SJohn Marino 	      gimple_set_lhs (stmt, new_lhs);
1301e4b17023SJohn Marino 	      changed = true;
1302e4b17023SJohn Marino 	    }
1303e4b17023SJohn Marino 	}
1304e4b17023SJohn Marino     }
1305e4b17023SJohn Marino 
1306e4b17023SJohn Marino   return changed;
1307e4b17023SJohn Marino }
1308e4b17023SJohn Marino 
1309e4b17023SJohn Marino /* Fold the statement pointed to by GSI.  In some cases, this function may
1310e4b17023SJohn Marino    replace the whole statement with a new one.  Returns true iff folding
1311e4b17023SJohn Marino    makes any changes.
1312e4b17023SJohn Marino    The statement pointed to by GSI should be in valid gimple form but may
1313e4b17023SJohn Marino    be in unfolded state as resulting from for example constant propagation
1314e4b17023SJohn Marino    which can produce *&x = 0.  */
1315e4b17023SJohn Marino 
1316e4b17023SJohn Marino bool
fold_stmt(gimple_stmt_iterator * gsi)1317e4b17023SJohn Marino fold_stmt (gimple_stmt_iterator *gsi)
1318e4b17023SJohn Marino {
1319e4b17023SJohn Marino   return fold_stmt_1 (gsi, false);
1320e4b17023SJohn Marino }
1321e4b17023SJohn Marino 
1322e4b17023SJohn Marino /* Perform the minimal folding on statement *GSI.  Only operations like
1323e4b17023SJohn Marino    *&x created by constant propagation are handled.  The statement cannot
1324e4b17023SJohn Marino    be replaced with a new one.  Return true if the statement was
1325e4b17023SJohn Marino    changed, false otherwise.
1326e4b17023SJohn Marino    The statement *GSI should be in valid gimple form but may
1327e4b17023SJohn Marino    be in unfolded state as resulting from for example constant propagation
1328e4b17023SJohn Marino    which can produce *&x = 0.  */
1329e4b17023SJohn Marino 
1330e4b17023SJohn Marino bool
fold_stmt_inplace(gimple_stmt_iterator * gsi)1331e4b17023SJohn Marino fold_stmt_inplace (gimple_stmt_iterator *gsi)
1332e4b17023SJohn Marino {
1333e4b17023SJohn Marino   gimple stmt = gsi_stmt (*gsi);
1334e4b17023SJohn Marino   bool changed = fold_stmt_1 (gsi, true);
1335e4b17023SJohn Marino   gcc_assert (gsi_stmt (*gsi) == stmt);
1336e4b17023SJohn Marino   return changed;
1337e4b17023SJohn Marino }
1338e4b17023SJohn Marino 
1339e4b17023SJohn Marino /* Canonicalize and possibly invert the boolean EXPR; return NULL_TREE
1340e4b17023SJohn Marino    if EXPR is null or we don't know how.
1341e4b17023SJohn Marino    If non-null, the result always has boolean type.  */
1342e4b17023SJohn Marino 
1343e4b17023SJohn Marino static tree
canonicalize_bool(tree expr,bool invert)1344e4b17023SJohn Marino canonicalize_bool (tree expr, bool invert)
1345e4b17023SJohn Marino {
1346e4b17023SJohn Marino   if (!expr)
1347e4b17023SJohn Marino     return NULL_TREE;
1348e4b17023SJohn Marino   else if (invert)
1349e4b17023SJohn Marino     {
1350e4b17023SJohn Marino       if (integer_nonzerop (expr))
1351e4b17023SJohn Marino 	return boolean_false_node;
1352e4b17023SJohn Marino       else if (integer_zerop (expr))
1353e4b17023SJohn Marino 	return boolean_true_node;
1354e4b17023SJohn Marino       else if (TREE_CODE (expr) == SSA_NAME)
1355e4b17023SJohn Marino 	return fold_build2 (EQ_EXPR, boolean_type_node, expr,
1356e4b17023SJohn Marino 			    build_int_cst (TREE_TYPE (expr), 0));
1357e4b17023SJohn Marino       else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison)
1358e4b17023SJohn Marino 	return fold_build2 (invert_tree_comparison (TREE_CODE (expr), false),
1359e4b17023SJohn Marino 			    boolean_type_node,
1360e4b17023SJohn Marino 			    TREE_OPERAND (expr, 0),
1361e4b17023SJohn Marino 			    TREE_OPERAND (expr, 1));
1362e4b17023SJohn Marino       else
1363e4b17023SJohn Marino 	return NULL_TREE;
1364e4b17023SJohn Marino     }
1365e4b17023SJohn Marino   else
1366e4b17023SJohn Marino     {
1367e4b17023SJohn Marino       if (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE)
1368e4b17023SJohn Marino 	return expr;
1369e4b17023SJohn Marino       if (integer_nonzerop (expr))
1370e4b17023SJohn Marino 	return boolean_true_node;
1371e4b17023SJohn Marino       else if (integer_zerop (expr))
1372e4b17023SJohn Marino 	return boolean_false_node;
1373e4b17023SJohn Marino       else if (TREE_CODE (expr) == SSA_NAME)
1374e4b17023SJohn Marino 	return fold_build2 (NE_EXPR, boolean_type_node, expr,
1375e4b17023SJohn Marino 			    build_int_cst (TREE_TYPE (expr), 0));
1376e4b17023SJohn Marino       else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison)
1377e4b17023SJohn Marino 	return fold_build2 (TREE_CODE (expr),
1378e4b17023SJohn Marino 			    boolean_type_node,
1379e4b17023SJohn Marino 			    TREE_OPERAND (expr, 0),
1380e4b17023SJohn Marino 			    TREE_OPERAND (expr, 1));
1381e4b17023SJohn Marino       else
1382e4b17023SJohn Marino 	return NULL_TREE;
1383e4b17023SJohn Marino     }
1384e4b17023SJohn Marino }
1385e4b17023SJohn Marino 
1386e4b17023SJohn Marino /* Check to see if a boolean expression EXPR is logically equivalent to the
1387e4b17023SJohn Marino    comparison (OP1 CODE OP2).  Check for various identities involving
1388e4b17023SJohn Marino    SSA_NAMEs.  */
1389e4b17023SJohn Marino 
1390e4b17023SJohn Marino static bool
same_bool_comparison_p(const_tree expr,enum tree_code code,const_tree op1,const_tree op2)1391e4b17023SJohn Marino same_bool_comparison_p (const_tree expr, enum tree_code code,
1392e4b17023SJohn Marino 			const_tree op1, const_tree op2)
1393e4b17023SJohn Marino {
1394e4b17023SJohn Marino   gimple s;
1395e4b17023SJohn Marino 
1396e4b17023SJohn Marino   /* The obvious case.  */
1397e4b17023SJohn Marino   if (TREE_CODE (expr) == code
1398e4b17023SJohn Marino       && operand_equal_p (TREE_OPERAND (expr, 0), op1, 0)
1399e4b17023SJohn Marino       && operand_equal_p (TREE_OPERAND (expr, 1), op2, 0))
1400e4b17023SJohn Marino     return true;
1401e4b17023SJohn Marino 
1402e4b17023SJohn Marino   /* Check for comparing (name, name != 0) and the case where expr
1403e4b17023SJohn Marino      is an SSA_NAME with a definition matching the comparison.  */
1404e4b17023SJohn Marino   if (TREE_CODE (expr) == SSA_NAME
1405e4b17023SJohn Marino       && TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE)
1406e4b17023SJohn Marino     {
1407e4b17023SJohn Marino       if (operand_equal_p (expr, op1, 0))
1408e4b17023SJohn Marino 	return ((code == NE_EXPR && integer_zerop (op2))
1409e4b17023SJohn Marino 		|| (code == EQ_EXPR && integer_nonzerop (op2)));
1410e4b17023SJohn Marino       s = SSA_NAME_DEF_STMT (expr);
1411e4b17023SJohn Marino       if (is_gimple_assign (s)
1412e4b17023SJohn Marino 	  && gimple_assign_rhs_code (s) == code
1413e4b17023SJohn Marino 	  && operand_equal_p (gimple_assign_rhs1 (s), op1, 0)
1414e4b17023SJohn Marino 	  && operand_equal_p (gimple_assign_rhs2 (s), op2, 0))
1415e4b17023SJohn Marino 	return true;
1416e4b17023SJohn Marino     }
1417e4b17023SJohn Marino 
1418e4b17023SJohn Marino   /* If op1 is of the form (name != 0) or (name == 0), and the definition
1419e4b17023SJohn Marino      of name is a comparison, recurse.  */
1420e4b17023SJohn Marino   if (TREE_CODE (op1) == SSA_NAME
1421e4b17023SJohn Marino       && TREE_CODE (TREE_TYPE (op1)) == BOOLEAN_TYPE)
1422e4b17023SJohn Marino     {
1423e4b17023SJohn Marino       s = SSA_NAME_DEF_STMT (op1);
1424e4b17023SJohn Marino       if (is_gimple_assign (s)
1425e4b17023SJohn Marino 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison)
1426e4b17023SJohn Marino 	{
1427e4b17023SJohn Marino 	  enum tree_code c = gimple_assign_rhs_code (s);
1428e4b17023SJohn Marino 	  if ((c == NE_EXPR && integer_zerop (op2))
1429e4b17023SJohn Marino 	      || (c == EQ_EXPR && integer_nonzerop (op2)))
1430e4b17023SJohn Marino 	    return same_bool_comparison_p (expr, c,
1431e4b17023SJohn Marino 					   gimple_assign_rhs1 (s),
1432e4b17023SJohn Marino 					   gimple_assign_rhs2 (s));
1433e4b17023SJohn Marino 	  if ((c == EQ_EXPR && integer_zerop (op2))
1434e4b17023SJohn Marino 	      || (c == NE_EXPR && integer_nonzerop (op2)))
1435e4b17023SJohn Marino 	    return same_bool_comparison_p (expr,
1436e4b17023SJohn Marino 					   invert_tree_comparison (c, false),
1437e4b17023SJohn Marino 					   gimple_assign_rhs1 (s),
1438e4b17023SJohn Marino 					   gimple_assign_rhs2 (s));
1439e4b17023SJohn Marino 	}
1440e4b17023SJohn Marino     }
1441e4b17023SJohn Marino   return false;
1442e4b17023SJohn Marino }
1443e4b17023SJohn Marino 
1444e4b17023SJohn Marino /* Check to see if two boolean expressions OP1 and OP2 are logically
1445e4b17023SJohn Marino    equivalent.  */
1446e4b17023SJohn Marino 
1447e4b17023SJohn Marino static bool
same_bool_result_p(const_tree op1,const_tree op2)1448e4b17023SJohn Marino same_bool_result_p (const_tree op1, const_tree op2)
1449e4b17023SJohn Marino {
1450e4b17023SJohn Marino   /* Simple cases first.  */
1451e4b17023SJohn Marino   if (operand_equal_p (op1, op2, 0))
1452e4b17023SJohn Marino     return true;
1453e4b17023SJohn Marino 
1454e4b17023SJohn Marino   /* Check the cases where at least one of the operands is a comparison.
1455e4b17023SJohn Marino      These are a bit smarter than operand_equal_p in that they apply some
1456e4b17023SJohn Marino      identifies on SSA_NAMEs.  */
1457e4b17023SJohn Marino   if (TREE_CODE_CLASS (TREE_CODE (op2)) == tcc_comparison
1458e4b17023SJohn Marino       && same_bool_comparison_p (op1, TREE_CODE (op2),
1459e4b17023SJohn Marino 				 TREE_OPERAND (op2, 0),
1460e4b17023SJohn Marino 				 TREE_OPERAND (op2, 1)))
1461e4b17023SJohn Marino     return true;
1462e4b17023SJohn Marino   if (TREE_CODE_CLASS (TREE_CODE (op1)) == tcc_comparison
1463e4b17023SJohn Marino       && same_bool_comparison_p (op2, TREE_CODE (op1),
1464e4b17023SJohn Marino 				 TREE_OPERAND (op1, 0),
1465e4b17023SJohn Marino 				 TREE_OPERAND (op1, 1)))
1466e4b17023SJohn Marino     return true;
1467e4b17023SJohn Marino 
1468e4b17023SJohn Marino   /* Default case.  */
1469e4b17023SJohn Marino   return false;
1470e4b17023SJohn Marino }
1471e4b17023SJohn Marino 
1472e4b17023SJohn Marino /* Forward declarations for some mutually recursive functions.  */
1473e4b17023SJohn Marino 
1474e4b17023SJohn Marino static tree
1475e4b17023SJohn Marino and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
1476e4b17023SJohn Marino 		   enum tree_code code2, tree op2a, tree op2b);
1477e4b17023SJohn Marino static tree
1478e4b17023SJohn Marino and_var_with_comparison (tree var, bool invert,
1479e4b17023SJohn Marino 			 enum tree_code code2, tree op2a, tree op2b);
1480e4b17023SJohn Marino static tree
1481e4b17023SJohn Marino and_var_with_comparison_1 (gimple stmt,
1482e4b17023SJohn Marino 			   enum tree_code code2, tree op2a, tree op2b);
1483e4b17023SJohn Marino static tree
1484e4b17023SJohn Marino or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
1485e4b17023SJohn Marino 		  enum tree_code code2, tree op2a, tree op2b);
1486e4b17023SJohn Marino static tree
1487e4b17023SJohn Marino or_var_with_comparison (tree var, bool invert,
1488e4b17023SJohn Marino 			enum tree_code code2, tree op2a, tree op2b);
1489e4b17023SJohn Marino static tree
1490e4b17023SJohn Marino or_var_with_comparison_1 (gimple stmt,
1491e4b17023SJohn Marino 			  enum tree_code code2, tree op2a, tree op2b);
1492e4b17023SJohn Marino 
1493e4b17023SJohn Marino /* Helper function for and_comparisons_1:  try to simplify the AND of the
1494e4b17023SJohn Marino    ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B).
1495e4b17023SJohn Marino    If INVERT is true, invert the value of the VAR before doing the AND.
1496e4b17023SJohn Marino    Return NULL_EXPR if we can't simplify this to a single expression.  */
1497e4b17023SJohn Marino 
1498e4b17023SJohn Marino static tree
and_var_with_comparison(tree var,bool invert,enum tree_code code2,tree op2a,tree op2b)1499e4b17023SJohn Marino and_var_with_comparison (tree var, bool invert,
1500e4b17023SJohn Marino 			 enum tree_code code2, tree op2a, tree op2b)
1501e4b17023SJohn Marino {
1502e4b17023SJohn Marino   tree t;
1503e4b17023SJohn Marino   gimple stmt = SSA_NAME_DEF_STMT (var);
1504e4b17023SJohn Marino 
1505e4b17023SJohn Marino   /* We can only deal with variables whose definitions are assignments.  */
1506e4b17023SJohn Marino   if (!is_gimple_assign (stmt))
1507e4b17023SJohn Marino     return NULL_TREE;
1508e4b17023SJohn Marino 
1509e4b17023SJohn Marino   /* If we have an inverted comparison, apply DeMorgan's law and rewrite
1510e4b17023SJohn Marino      !var AND (op2a code2 op2b) => !(var OR !(op2a code2 op2b))
1511e4b17023SJohn Marino      Then we only have to consider the simpler non-inverted cases.  */
1512e4b17023SJohn Marino   if (invert)
1513e4b17023SJohn Marino     t = or_var_with_comparison_1 (stmt,
1514e4b17023SJohn Marino 				  invert_tree_comparison (code2, false),
1515e4b17023SJohn Marino 				  op2a, op2b);
1516e4b17023SJohn Marino   else
1517e4b17023SJohn Marino     t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
1518e4b17023SJohn Marino   return canonicalize_bool (t, invert);
1519e4b17023SJohn Marino }
1520e4b17023SJohn Marino 
1521e4b17023SJohn Marino /* Try to simplify the AND of the ssa variable defined by the assignment
1522e4b17023SJohn Marino    STMT with the comparison specified by (OP2A CODE2 OP2B).
1523e4b17023SJohn Marino    Return NULL_EXPR if we can't simplify this to a single expression.  */
1524e4b17023SJohn Marino 
1525e4b17023SJohn Marino static tree
and_var_with_comparison_1(gimple stmt,enum tree_code code2,tree op2a,tree op2b)1526e4b17023SJohn Marino and_var_with_comparison_1 (gimple stmt,
1527e4b17023SJohn Marino 			   enum tree_code code2, tree op2a, tree op2b)
1528e4b17023SJohn Marino {
1529e4b17023SJohn Marino   tree var = gimple_assign_lhs (stmt);
1530e4b17023SJohn Marino   tree true_test_var = NULL_TREE;
1531e4b17023SJohn Marino   tree false_test_var = NULL_TREE;
1532e4b17023SJohn Marino   enum tree_code innercode = gimple_assign_rhs_code (stmt);
1533e4b17023SJohn Marino 
1534e4b17023SJohn Marino   /* Check for identities like (var AND (var == 0)) => false.  */
1535e4b17023SJohn Marino   if (TREE_CODE (op2a) == SSA_NAME
1536e4b17023SJohn Marino       && TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE)
1537e4b17023SJohn Marino     {
1538e4b17023SJohn Marino       if ((code2 == NE_EXPR && integer_zerop (op2b))
1539e4b17023SJohn Marino 	  || (code2 == EQ_EXPR && integer_nonzerop (op2b)))
1540e4b17023SJohn Marino 	{
1541e4b17023SJohn Marino 	  true_test_var = op2a;
1542e4b17023SJohn Marino 	  if (var == true_test_var)
1543e4b17023SJohn Marino 	    return var;
1544e4b17023SJohn Marino 	}
1545e4b17023SJohn Marino       else if ((code2 == EQ_EXPR && integer_zerop (op2b))
1546e4b17023SJohn Marino 	       || (code2 == NE_EXPR && integer_nonzerop (op2b)))
1547e4b17023SJohn Marino 	{
1548e4b17023SJohn Marino 	  false_test_var = op2a;
1549e4b17023SJohn Marino 	  if (var == false_test_var)
1550e4b17023SJohn Marino 	    return boolean_false_node;
1551e4b17023SJohn Marino 	}
1552e4b17023SJohn Marino     }
1553e4b17023SJohn Marino 
1554e4b17023SJohn Marino   /* If the definition is a comparison, recurse on it.  */
1555e4b17023SJohn Marino   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
1556e4b17023SJohn Marino     {
1557e4b17023SJohn Marino       tree t = and_comparisons_1 (innercode,
1558e4b17023SJohn Marino 				  gimple_assign_rhs1 (stmt),
1559e4b17023SJohn Marino 				  gimple_assign_rhs2 (stmt),
1560e4b17023SJohn Marino 				  code2,
1561e4b17023SJohn Marino 				  op2a,
1562e4b17023SJohn Marino 				  op2b);
1563e4b17023SJohn Marino       if (t)
1564e4b17023SJohn Marino 	return t;
1565e4b17023SJohn Marino     }
1566e4b17023SJohn Marino 
1567e4b17023SJohn Marino   /* If the definition is an AND or OR expression, we may be able to
1568e4b17023SJohn Marino      simplify by reassociating.  */
1569e4b17023SJohn Marino   if (TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE
1570e4b17023SJohn Marino       && (innercode == BIT_AND_EXPR || innercode == BIT_IOR_EXPR))
1571e4b17023SJohn Marino     {
1572e4b17023SJohn Marino       tree inner1 = gimple_assign_rhs1 (stmt);
1573e4b17023SJohn Marino       tree inner2 = gimple_assign_rhs2 (stmt);
1574e4b17023SJohn Marino       gimple s;
1575e4b17023SJohn Marino       tree t;
1576e4b17023SJohn Marino       tree partial = NULL_TREE;
1577e4b17023SJohn Marino       bool is_and = (innercode == BIT_AND_EXPR);
1578e4b17023SJohn Marino 
1579e4b17023SJohn Marino       /* Check for boolean identities that don't require recursive examination
1580e4b17023SJohn Marino 	 of inner1/inner2:
1581e4b17023SJohn Marino 	 inner1 AND (inner1 AND inner2) => inner1 AND inner2 => var
1582e4b17023SJohn Marino 	 inner1 AND (inner1 OR inner2) => inner1
1583e4b17023SJohn Marino 	 !inner1 AND (inner1 AND inner2) => false
1584e4b17023SJohn Marino 	 !inner1 AND (inner1 OR inner2) => !inner1 AND inner2
1585e4b17023SJohn Marino          Likewise for similar cases involving inner2.  */
1586e4b17023SJohn Marino       if (inner1 == true_test_var)
1587e4b17023SJohn Marino 	return (is_and ? var : inner1);
1588e4b17023SJohn Marino       else if (inner2 == true_test_var)
1589e4b17023SJohn Marino 	return (is_and ? var : inner2);
1590e4b17023SJohn Marino       else if (inner1 == false_test_var)
1591e4b17023SJohn Marino 	return (is_and
1592e4b17023SJohn Marino 		? boolean_false_node
1593e4b17023SJohn Marino 		: and_var_with_comparison (inner2, false, code2, op2a, op2b));
1594e4b17023SJohn Marino       else if (inner2 == false_test_var)
1595e4b17023SJohn Marino 	return (is_and
1596e4b17023SJohn Marino 		? boolean_false_node
1597e4b17023SJohn Marino 		: and_var_with_comparison (inner1, false, code2, op2a, op2b));
1598e4b17023SJohn Marino 
1599e4b17023SJohn Marino       /* Next, redistribute/reassociate the AND across the inner tests.
1600e4b17023SJohn Marino 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
1601e4b17023SJohn Marino       if (TREE_CODE (inner1) == SSA_NAME
1602e4b17023SJohn Marino 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
1603e4b17023SJohn Marino 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
1604e4b17023SJohn Marino 	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
1605e4b17023SJohn Marino 					      gimple_assign_rhs1 (s),
1606e4b17023SJohn Marino 					      gimple_assign_rhs2 (s),
1607e4b17023SJohn Marino 					      code2, op2a, op2b)))
1608e4b17023SJohn Marino 	{
1609e4b17023SJohn Marino 	  /* Handle the AND case, where we are reassociating:
1610e4b17023SJohn Marino 	     (inner1 AND inner2) AND (op2a code2 op2b)
1611e4b17023SJohn Marino 	     => (t AND inner2)
1612e4b17023SJohn Marino 	     If the partial result t is a constant, we win.  Otherwise
1613e4b17023SJohn Marino 	     continue on to try reassociating with the other inner test.  */
1614e4b17023SJohn Marino 	  if (is_and)
1615e4b17023SJohn Marino 	    {
1616e4b17023SJohn Marino 	      if (integer_onep (t))
1617e4b17023SJohn Marino 		return inner2;
1618e4b17023SJohn Marino 	      else if (integer_zerop (t))
1619e4b17023SJohn Marino 		return boolean_false_node;
1620e4b17023SJohn Marino 	    }
1621e4b17023SJohn Marino 
1622e4b17023SJohn Marino 	  /* Handle the OR case, where we are redistributing:
1623e4b17023SJohn Marino 	     (inner1 OR inner2) AND (op2a code2 op2b)
1624e4b17023SJohn Marino 	     => (t OR (inner2 AND (op2a code2 op2b)))  */
1625e4b17023SJohn Marino 	  else if (integer_onep (t))
1626e4b17023SJohn Marino 	    return boolean_true_node;
1627e4b17023SJohn Marino 
1628e4b17023SJohn Marino 	  /* Save partial result for later.  */
1629e4b17023SJohn Marino 	  partial = t;
1630e4b17023SJohn Marino 	}
1631e4b17023SJohn Marino 
1632e4b17023SJohn Marino       /* Compute the second partial result, (inner2 AND (op2a code op2b)) */
1633e4b17023SJohn Marino       if (TREE_CODE (inner2) == SSA_NAME
1634e4b17023SJohn Marino 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
1635e4b17023SJohn Marino 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
1636e4b17023SJohn Marino 	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
1637e4b17023SJohn Marino 					      gimple_assign_rhs1 (s),
1638e4b17023SJohn Marino 					      gimple_assign_rhs2 (s),
1639e4b17023SJohn Marino 					      code2, op2a, op2b)))
1640e4b17023SJohn Marino 	{
1641e4b17023SJohn Marino 	  /* Handle the AND case, where we are reassociating:
1642e4b17023SJohn Marino 	     (inner1 AND inner2) AND (op2a code2 op2b)
1643e4b17023SJohn Marino 	     => (inner1 AND t)  */
1644e4b17023SJohn Marino 	  if (is_and)
1645e4b17023SJohn Marino 	    {
1646e4b17023SJohn Marino 	      if (integer_onep (t))
1647e4b17023SJohn Marino 		return inner1;
1648e4b17023SJohn Marino 	      else if (integer_zerop (t))
1649e4b17023SJohn Marino 		return boolean_false_node;
1650e4b17023SJohn Marino 	      /* If both are the same, we can apply the identity
1651e4b17023SJohn Marino 		 (x AND x) == x.  */
1652e4b17023SJohn Marino 	      else if (partial && same_bool_result_p (t, partial))
1653e4b17023SJohn Marino 		return t;
1654e4b17023SJohn Marino 	    }
1655e4b17023SJohn Marino 
1656e4b17023SJohn Marino 	  /* Handle the OR case. where we are redistributing:
1657e4b17023SJohn Marino 	     (inner1 OR inner2) AND (op2a code2 op2b)
1658e4b17023SJohn Marino 	     => (t OR (inner1 AND (op2a code2 op2b)))
1659e4b17023SJohn Marino 	     => (t OR partial)  */
1660e4b17023SJohn Marino 	  else
1661e4b17023SJohn Marino 	    {
1662e4b17023SJohn Marino 	      if (integer_onep (t))
1663e4b17023SJohn Marino 		return boolean_true_node;
1664e4b17023SJohn Marino 	      else if (partial)
1665e4b17023SJohn Marino 		{
1666e4b17023SJohn Marino 		  /* We already got a simplification for the other
1667e4b17023SJohn Marino 		     operand to the redistributed OR expression.  The
1668e4b17023SJohn Marino 		     interesting case is when at least one is false.
1669e4b17023SJohn Marino 		     Or, if both are the same, we can apply the identity
1670e4b17023SJohn Marino 		     (x OR x) == x.  */
1671e4b17023SJohn Marino 		  if (integer_zerop (partial))
1672e4b17023SJohn Marino 		    return t;
1673e4b17023SJohn Marino 		  else if (integer_zerop (t))
1674e4b17023SJohn Marino 		    return partial;
1675e4b17023SJohn Marino 		  else if (same_bool_result_p (t, partial))
1676e4b17023SJohn Marino 		    return t;
1677e4b17023SJohn Marino 		}
1678e4b17023SJohn Marino 	    }
1679e4b17023SJohn Marino 	}
1680e4b17023SJohn Marino     }
1681e4b17023SJohn Marino   return NULL_TREE;
1682e4b17023SJohn Marino }
1683e4b17023SJohn Marino 
1684e4b17023SJohn Marino /* Try to simplify the AND of two comparisons defined by
1685e4b17023SJohn Marino    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
1686e4b17023SJohn Marino    If this can be done without constructing an intermediate value,
1687e4b17023SJohn Marino    return the resulting tree; otherwise NULL_TREE is returned.
1688e4b17023SJohn Marino    This function is deliberately asymmetric as it recurses on SSA_DEFs
1689e4b17023SJohn Marino    in the first comparison but not the second.  */
1690e4b17023SJohn Marino 
1691e4b17023SJohn Marino static tree
and_comparisons_1(enum tree_code code1,tree op1a,tree op1b,enum tree_code code2,tree op2a,tree op2b)1692e4b17023SJohn Marino and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
1693e4b17023SJohn Marino 		   enum tree_code code2, tree op2a, tree op2b)
1694e4b17023SJohn Marino {
1695e4b17023SJohn Marino   /* First check for ((x CODE1 y) AND (x CODE2 y)).  */
1696e4b17023SJohn Marino   if (operand_equal_p (op1a, op2a, 0)
1697e4b17023SJohn Marino       && operand_equal_p (op1b, op2b, 0))
1698e4b17023SJohn Marino     {
1699e4b17023SJohn Marino       /* Result will be either NULL_TREE, or a combined comparison.  */
1700e4b17023SJohn Marino       tree t = combine_comparisons (UNKNOWN_LOCATION,
1701e4b17023SJohn Marino 				    TRUTH_ANDIF_EXPR, code1, code2,
1702e4b17023SJohn Marino 				    boolean_type_node, op1a, op1b);
1703e4b17023SJohn Marino       if (t)
1704e4b17023SJohn Marino 	return t;
1705e4b17023SJohn Marino     }
1706e4b17023SJohn Marino 
1707e4b17023SJohn Marino   /* Likewise the swapped case of the above.  */
1708e4b17023SJohn Marino   if (operand_equal_p (op1a, op2b, 0)
1709e4b17023SJohn Marino       && operand_equal_p (op1b, op2a, 0))
1710e4b17023SJohn Marino     {
1711e4b17023SJohn Marino       /* Result will be either NULL_TREE, or a combined comparison.  */
1712e4b17023SJohn Marino       tree t = combine_comparisons (UNKNOWN_LOCATION,
1713e4b17023SJohn Marino 				    TRUTH_ANDIF_EXPR, code1,
1714e4b17023SJohn Marino 				    swap_tree_comparison (code2),
1715e4b17023SJohn Marino 				    boolean_type_node, op1a, op1b);
1716e4b17023SJohn Marino       if (t)
1717e4b17023SJohn Marino 	return t;
1718e4b17023SJohn Marino     }
1719e4b17023SJohn Marino 
1720e4b17023SJohn Marino   /* If both comparisons are of the same value against constants, we might
1721e4b17023SJohn Marino      be able to merge them.  */
1722e4b17023SJohn Marino   if (operand_equal_p (op1a, op2a, 0)
1723e4b17023SJohn Marino       && TREE_CODE (op1b) == INTEGER_CST
1724e4b17023SJohn Marino       && TREE_CODE (op2b) == INTEGER_CST)
1725e4b17023SJohn Marino     {
1726e4b17023SJohn Marino       int cmp = tree_int_cst_compare (op1b, op2b);
1727e4b17023SJohn Marino 
1728e4b17023SJohn Marino       /* If we have (op1a == op1b), we should either be able to
1729e4b17023SJohn Marino 	 return that or FALSE, depending on whether the constant op1b
1730e4b17023SJohn Marino 	 also satisfies the other comparison against op2b.  */
1731e4b17023SJohn Marino       if (code1 == EQ_EXPR)
1732e4b17023SJohn Marino 	{
1733e4b17023SJohn Marino 	  bool done = true;
1734e4b17023SJohn Marino 	  bool val;
1735e4b17023SJohn Marino 	  switch (code2)
1736e4b17023SJohn Marino 	    {
1737e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
1738e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
1739e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp < 0); break;
1740e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp > 0); break;
1741e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp <= 0); break;
1742e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp >= 0); break;
1743e4b17023SJohn Marino 	    default: done = false;
1744e4b17023SJohn Marino 	    }
1745e4b17023SJohn Marino 	  if (done)
1746e4b17023SJohn Marino 	    {
1747e4b17023SJohn Marino 	      if (val)
1748e4b17023SJohn Marino 		return fold_build2 (code1, boolean_type_node, op1a, op1b);
1749e4b17023SJohn Marino 	      else
1750e4b17023SJohn Marino 		return boolean_false_node;
1751e4b17023SJohn Marino 	    }
1752e4b17023SJohn Marino 	}
1753e4b17023SJohn Marino       /* Likewise if the second comparison is an == comparison.  */
1754e4b17023SJohn Marino       else if (code2 == EQ_EXPR)
1755e4b17023SJohn Marino 	{
1756e4b17023SJohn Marino 	  bool done = true;
1757e4b17023SJohn Marino 	  bool val;
1758e4b17023SJohn Marino 	  switch (code1)
1759e4b17023SJohn Marino 	    {
1760e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
1761e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
1762e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp > 0); break;
1763e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp < 0); break;
1764e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp >= 0); break;
1765e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp <= 0); break;
1766e4b17023SJohn Marino 	    default: done = false;
1767e4b17023SJohn Marino 	    }
1768e4b17023SJohn Marino 	  if (done)
1769e4b17023SJohn Marino 	    {
1770e4b17023SJohn Marino 	      if (val)
1771e4b17023SJohn Marino 		return fold_build2 (code2, boolean_type_node, op2a, op2b);
1772e4b17023SJohn Marino 	      else
1773e4b17023SJohn Marino 		return boolean_false_node;
1774e4b17023SJohn Marino 	    }
1775e4b17023SJohn Marino 	}
1776e4b17023SJohn Marino 
1777e4b17023SJohn Marino       /* Same business with inequality tests.  */
1778e4b17023SJohn Marino       else if (code1 == NE_EXPR)
1779e4b17023SJohn Marino 	{
1780e4b17023SJohn Marino 	  bool val;
1781e4b17023SJohn Marino 	  switch (code2)
1782e4b17023SJohn Marino 	    {
1783e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp != 0); break;
1784e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp == 0); break;
1785e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp >= 0); break;
1786e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp <= 0); break;
1787e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp > 0); break;
1788e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp < 0); break;
1789e4b17023SJohn Marino 	    default:
1790e4b17023SJohn Marino 	      val = false;
1791e4b17023SJohn Marino 	    }
1792e4b17023SJohn Marino 	  if (val)
1793e4b17023SJohn Marino 	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
1794e4b17023SJohn Marino 	}
1795e4b17023SJohn Marino       else if (code2 == NE_EXPR)
1796e4b17023SJohn Marino 	{
1797e4b17023SJohn Marino 	  bool val;
1798e4b17023SJohn Marino 	  switch (code1)
1799e4b17023SJohn Marino 	    {
1800e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
1801e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
1802e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp <= 0); break;
1803e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp >= 0); break;
1804e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp < 0); break;
1805e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp > 0); break;
1806e4b17023SJohn Marino 	    default:
1807e4b17023SJohn Marino 	      val = false;
1808e4b17023SJohn Marino 	    }
1809e4b17023SJohn Marino 	  if (val)
1810e4b17023SJohn Marino 	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
1811e4b17023SJohn Marino 	}
1812e4b17023SJohn Marino 
1813e4b17023SJohn Marino       /* Chose the more restrictive of two < or <= comparisons.  */
1814e4b17023SJohn Marino       else if ((code1 == LT_EXPR || code1 == LE_EXPR)
1815e4b17023SJohn Marino 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
1816e4b17023SJohn Marino 	{
1817e4b17023SJohn Marino 	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
1818e4b17023SJohn Marino 	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
1819e4b17023SJohn Marino 	  else
1820e4b17023SJohn Marino 	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
1821e4b17023SJohn Marino 	}
1822e4b17023SJohn Marino 
1823e4b17023SJohn Marino       /* Likewise chose the more restrictive of two > or >= comparisons.  */
1824e4b17023SJohn Marino       else if ((code1 == GT_EXPR || code1 == GE_EXPR)
1825e4b17023SJohn Marino 	       && (code2 == GT_EXPR || code2 == GE_EXPR))
1826e4b17023SJohn Marino 	{
1827e4b17023SJohn Marino 	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
1828e4b17023SJohn Marino 	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
1829e4b17023SJohn Marino 	  else
1830e4b17023SJohn Marino 	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
1831e4b17023SJohn Marino 	}
1832e4b17023SJohn Marino 
1833e4b17023SJohn Marino       /* Check for singleton ranges.  */
1834e4b17023SJohn Marino       else if (cmp == 0
1835e4b17023SJohn Marino 	       && ((code1 == LE_EXPR && code2 == GE_EXPR)
1836e4b17023SJohn Marino 		   || (code1 == GE_EXPR && code2 == LE_EXPR)))
1837e4b17023SJohn Marino 	return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
1838e4b17023SJohn Marino 
1839e4b17023SJohn Marino       /* Check for disjoint ranges. */
1840e4b17023SJohn Marino       else if (cmp <= 0
1841e4b17023SJohn Marino 	       && (code1 == LT_EXPR || code1 == LE_EXPR)
1842e4b17023SJohn Marino 	       && (code2 == GT_EXPR || code2 == GE_EXPR))
1843e4b17023SJohn Marino 	return boolean_false_node;
1844e4b17023SJohn Marino       else if (cmp >= 0
1845e4b17023SJohn Marino 	       && (code1 == GT_EXPR || code1 == GE_EXPR)
1846e4b17023SJohn Marino 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
1847e4b17023SJohn Marino 	return boolean_false_node;
1848e4b17023SJohn Marino     }
1849e4b17023SJohn Marino 
1850e4b17023SJohn Marino   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
1851e4b17023SJohn Marino      NAME's definition is a truth value.  See if there are any simplifications
1852e4b17023SJohn Marino      that can be done against the NAME's definition.  */
1853e4b17023SJohn Marino   if (TREE_CODE (op1a) == SSA_NAME
1854e4b17023SJohn Marino       && (code1 == NE_EXPR || code1 == EQ_EXPR)
1855e4b17023SJohn Marino       && (integer_zerop (op1b) || integer_onep (op1b)))
1856e4b17023SJohn Marino     {
1857e4b17023SJohn Marino       bool invert = ((code1 == EQ_EXPR && integer_zerop (op1b))
1858e4b17023SJohn Marino 		     || (code1 == NE_EXPR && integer_onep (op1b)));
1859e4b17023SJohn Marino       gimple stmt = SSA_NAME_DEF_STMT (op1a);
1860e4b17023SJohn Marino       switch (gimple_code (stmt))
1861e4b17023SJohn Marino 	{
1862e4b17023SJohn Marino 	case GIMPLE_ASSIGN:
1863e4b17023SJohn Marino 	  /* Try to simplify by copy-propagating the definition.  */
1864e4b17023SJohn Marino 	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
1865e4b17023SJohn Marino 
1866e4b17023SJohn Marino 	case GIMPLE_PHI:
1867e4b17023SJohn Marino 	  /* If every argument to the PHI produces the same result when
1868e4b17023SJohn Marino 	     ANDed with the second comparison, we win.
1869e4b17023SJohn Marino 	     Do not do this unless the type is bool since we need a bool
1870e4b17023SJohn Marino 	     result here anyway.  */
1871e4b17023SJohn Marino 	  if (TREE_CODE (TREE_TYPE (op1a)) == BOOLEAN_TYPE)
1872e4b17023SJohn Marino 	    {
1873e4b17023SJohn Marino 	      tree result = NULL_TREE;
1874e4b17023SJohn Marino 	      unsigned i;
1875e4b17023SJohn Marino 	      for (i = 0; i < gimple_phi_num_args (stmt); i++)
1876e4b17023SJohn Marino 		{
1877e4b17023SJohn Marino 		  tree arg = gimple_phi_arg_def (stmt, i);
1878e4b17023SJohn Marino 
1879e4b17023SJohn Marino 		  /* If this PHI has itself as an argument, ignore it.
1880e4b17023SJohn Marino 		     If all the other args produce the same result,
1881e4b17023SJohn Marino 		     we're still OK.  */
1882e4b17023SJohn Marino 		  if (arg == gimple_phi_result (stmt))
1883e4b17023SJohn Marino 		    continue;
1884e4b17023SJohn Marino 		  else if (TREE_CODE (arg) == INTEGER_CST)
1885e4b17023SJohn Marino 		    {
1886e4b17023SJohn Marino 		      if (invert ? integer_nonzerop (arg) : integer_zerop (arg))
1887e4b17023SJohn Marino 			{
1888e4b17023SJohn Marino 			  if (!result)
1889e4b17023SJohn Marino 			    result = boolean_false_node;
1890e4b17023SJohn Marino 			  else if (!integer_zerop (result))
1891e4b17023SJohn Marino 			    return NULL_TREE;
1892e4b17023SJohn Marino 			}
1893e4b17023SJohn Marino 		      else if (!result)
1894e4b17023SJohn Marino 			result = fold_build2 (code2, boolean_type_node,
1895e4b17023SJohn Marino 					      op2a, op2b);
1896e4b17023SJohn Marino 		      else if (!same_bool_comparison_p (result,
1897e4b17023SJohn Marino 							code2, op2a, op2b))
1898e4b17023SJohn Marino 			return NULL_TREE;
1899e4b17023SJohn Marino 		    }
1900e4b17023SJohn Marino 		  else if (TREE_CODE (arg) == SSA_NAME
1901e4b17023SJohn Marino 			   && !SSA_NAME_IS_DEFAULT_DEF (arg))
1902e4b17023SJohn Marino 		    {
1903e4b17023SJohn Marino 		      tree temp;
1904e4b17023SJohn Marino 		      gimple def_stmt = SSA_NAME_DEF_STMT (arg);
1905e4b17023SJohn Marino 		      /* In simple cases we can look through PHI nodes,
1906e4b17023SJohn Marino 			 but we have to be careful with loops.
1907e4b17023SJohn Marino 			 See PR49073.  */
1908e4b17023SJohn Marino 		      if (! dom_info_available_p (CDI_DOMINATORS)
1909e4b17023SJohn Marino 			  || gimple_bb (def_stmt) == gimple_bb (stmt)
1910e4b17023SJohn Marino 			  || dominated_by_p (CDI_DOMINATORS,
1911e4b17023SJohn Marino 					     gimple_bb (def_stmt),
1912e4b17023SJohn Marino 					     gimple_bb (stmt)))
1913e4b17023SJohn Marino 			return NULL_TREE;
1914e4b17023SJohn Marino 		      temp = and_var_with_comparison (arg, invert, code2,
1915e4b17023SJohn Marino 						      op2a, op2b);
1916e4b17023SJohn Marino 		      if (!temp)
1917e4b17023SJohn Marino 			return NULL_TREE;
1918e4b17023SJohn Marino 		      else if (!result)
1919e4b17023SJohn Marino 			result = temp;
1920e4b17023SJohn Marino 		      else if (!same_bool_result_p (result, temp))
1921e4b17023SJohn Marino 			return NULL_TREE;
1922e4b17023SJohn Marino 		    }
1923e4b17023SJohn Marino 		  else
1924e4b17023SJohn Marino 		    return NULL_TREE;
1925e4b17023SJohn Marino 		}
1926e4b17023SJohn Marino 	      return result;
1927e4b17023SJohn Marino 	    }
1928e4b17023SJohn Marino 
1929e4b17023SJohn Marino 	default:
1930e4b17023SJohn Marino 	  break;
1931e4b17023SJohn Marino 	}
1932e4b17023SJohn Marino     }
1933e4b17023SJohn Marino   return NULL_TREE;
1934e4b17023SJohn Marino }
1935e4b17023SJohn Marino 
1936e4b17023SJohn Marino /* Try to simplify the AND of two comparisons, specified by
1937e4b17023SJohn Marino    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
1938e4b17023SJohn Marino    If this can be simplified to a single expression (without requiring
1939e4b17023SJohn Marino    introducing more SSA variables to hold intermediate values),
1940e4b17023SJohn Marino    return the resulting tree.  Otherwise return NULL_TREE.
1941e4b17023SJohn Marino    If the result expression is non-null, it has boolean type.  */
1942e4b17023SJohn Marino 
1943e4b17023SJohn Marino tree
maybe_fold_and_comparisons(enum tree_code code1,tree op1a,tree op1b,enum tree_code code2,tree op2a,tree op2b)1944e4b17023SJohn Marino maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
1945e4b17023SJohn Marino 			    enum tree_code code2, tree op2a, tree op2b)
1946e4b17023SJohn Marino {
1947e4b17023SJohn Marino   tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
1948e4b17023SJohn Marino   if (t)
1949e4b17023SJohn Marino     return t;
1950e4b17023SJohn Marino   else
1951e4b17023SJohn Marino     return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
1952e4b17023SJohn Marino }
1953e4b17023SJohn Marino 
1954e4b17023SJohn Marino /* Helper function for or_comparisons_1:  try to simplify the OR of the
1955e4b17023SJohn Marino    ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B).
1956e4b17023SJohn Marino    If INVERT is true, invert the value of VAR before doing the OR.
1957e4b17023SJohn Marino    Return NULL_EXPR if we can't simplify this to a single expression.  */
1958e4b17023SJohn Marino 
1959e4b17023SJohn Marino static tree
or_var_with_comparison(tree var,bool invert,enum tree_code code2,tree op2a,tree op2b)1960e4b17023SJohn Marino or_var_with_comparison (tree var, bool invert,
1961e4b17023SJohn Marino 			enum tree_code code2, tree op2a, tree op2b)
1962e4b17023SJohn Marino {
1963e4b17023SJohn Marino   tree t;
1964e4b17023SJohn Marino   gimple stmt = SSA_NAME_DEF_STMT (var);
1965e4b17023SJohn Marino 
1966e4b17023SJohn Marino   /* We can only deal with variables whose definitions are assignments.  */
1967e4b17023SJohn Marino   if (!is_gimple_assign (stmt))
1968e4b17023SJohn Marino     return NULL_TREE;
1969e4b17023SJohn Marino 
1970e4b17023SJohn Marino   /* If we have an inverted comparison, apply DeMorgan's law and rewrite
1971e4b17023SJohn Marino      !var OR (op2a code2 op2b) => !(var AND !(op2a code2 op2b))
1972e4b17023SJohn Marino      Then we only have to consider the simpler non-inverted cases.  */
1973e4b17023SJohn Marino   if (invert)
1974e4b17023SJohn Marino     t = and_var_with_comparison_1 (stmt,
1975e4b17023SJohn Marino 				   invert_tree_comparison (code2, false),
1976e4b17023SJohn Marino 				   op2a, op2b);
1977e4b17023SJohn Marino   else
1978e4b17023SJohn Marino     t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
1979e4b17023SJohn Marino   return canonicalize_bool (t, invert);
1980e4b17023SJohn Marino }
1981e4b17023SJohn Marino 
1982e4b17023SJohn Marino /* Try to simplify the OR of the ssa variable defined by the assignment
1983e4b17023SJohn Marino    STMT with the comparison specified by (OP2A CODE2 OP2B).
1984e4b17023SJohn Marino    Return NULL_EXPR if we can't simplify this to a single expression.  */
1985e4b17023SJohn Marino 
1986e4b17023SJohn Marino static tree
or_var_with_comparison_1(gimple stmt,enum tree_code code2,tree op2a,tree op2b)1987e4b17023SJohn Marino or_var_with_comparison_1 (gimple stmt,
1988e4b17023SJohn Marino 			  enum tree_code code2, tree op2a, tree op2b)
1989e4b17023SJohn Marino {
1990e4b17023SJohn Marino   tree var = gimple_assign_lhs (stmt);
1991e4b17023SJohn Marino   tree true_test_var = NULL_TREE;
1992e4b17023SJohn Marino   tree false_test_var = NULL_TREE;
1993e4b17023SJohn Marino   enum tree_code innercode = gimple_assign_rhs_code (stmt);
1994e4b17023SJohn Marino 
1995e4b17023SJohn Marino   /* Check for identities like (var OR (var != 0)) => true .  */
1996e4b17023SJohn Marino   if (TREE_CODE (op2a) == SSA_NAME
1997e4b17023SJohn Marino       && TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE)
1998e4b17023SJohn Marino     {
1999e4b17023SJohn Marino       if ((code2 == NE_EXPR && integer_zerop (op2b))
2000e4b17023SJohn Marino 	  || (code2 == EQ_EXPR && integer_nonzerop (op2b)))
2001e4b17023SJohn Marino 	{
2002e4b17023SJohn Marino 	  true_test_var = op2a;
2003e4b17023SJohn Marino 	  if (var == true_test_var)
2004e4b17023SJohn Marino 	    return var;
2005e4b17023SJohn Marino 	}
2006e4b17023SJohn Marino       else if ((code2 == EQ_EXPR && integer_zerop (op2b))
2007e4b17023SJohn Marino 	       || (code2 == NE_EXPR && integer_nonzerop (op2b)))
2008e4b17023SJohn Marino 	{
2009e4b17023SJohn Marino 	  false_test_var = op2a;
2010e4b17023SJohn Marino 	  if (var == false_test_var)
2011e4b17023SJohn Marino 	    return boolean_true_node;
2012e4b17023SJohn Marino 	}
2013e4b17023SJohn Marino     }
2014e4b17023SJohn Marino 
2015e4b17023SJohn Marino   /* If the definition is a comparison, recurse on it.  */
2016e4b17023SJohn Marino   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
2017e4b17023SJohn Marino     {
2018e4b17023SJohn Marino       tree t = or_comparisons_1 (innercode,
2019e4b17023SJohn Marino 				 gimple_assign_rhs1 (stmt),
2020e4b17023SJohn Marino 				 gimple_assign_rhs2 (stmt),
2021e4b17023SJohn Marino 				 code2,
2022e4b17023SJohn Marino 				 op2a,
2023e4b17023SJohn Marino 				 op2b);
2024e4b17023SJohn Marino       if (t)
2025e4b17023SJohn Marino 	return t;
2026e4b17023SJohn Marino     }
2027e4b17023SJohn Marino 
2028e4b17023SJohn Marino   /* If the definition is an AND or OR expression, we may be able to
2029e4b17023SJohn Marino      simplify by reassociating.  */
2030e4b17023SJohn Marino   if (TREE_CODE (TREE_TYPE (var)) == BOOLEAN_TYPE
2031e4b17023SJohn Marino       && (innercode == BIT_AND_EXPR || innercode == BIT_IOR_EXPR))
2032e4b17023SJohn Marino     {
2033e4b17023SJohn Marino       tree inner1 = gimple_assign_rhs1 (stmt);
2034e4b17023SJohn Marino       tree inner2 = gimple_assign_rhs2 (stmt);
2035e4b17023SJohn Marino       gimple s;
2036e4b17023SJohn Marino       tree t;
2037e4b17023SJohn Marino       tree partial = NULL_TREE;
2038e4b17023SJohn Marino       bool is_or = (innercode == BIT_IOR_EXPR);
2039e4b17023SJohn Marino 
2040e4b17023SJohn Marino       /* Check for boolean identities that don't require recursive examination
2041e4b17023SJohn Marino 	 of inner1/inner2:
2042e4b17023SJohn Marino 	 inner1 OR (inner1 OR inner2) => inner1 OR inner2 => var
2043e4b17023SJohn Marino 	 inner1 OR (inner1 AND inner2) => inner1
2044e4b17023SJohn Marino 	 !inner1 OR (inner1 OR inner2) => true
2045e4b17023SJohn Marino 	 !inner1 OR (inner1 AND inner2) => !inner1 OR inner2
2046e4b17023SJohn Marino       */
2047e4b17023SJohn Marino       if (inner1 == true_test_var)
2048e4b17023SJohn Marino 	return (is_or ? var : inner1);
2049e4b17023SJohn Marino       else if (inner2 == true_test_var)
2050e4b17023SJohn Marino 	return (is_or ? var : inner2);
2051e4b17023SJohn Marino       else if (inner1 == false_test_var)
2052e4b17023SJohn Marino 	return (is_or
2053e4b17023SJohn Marino 		? boolean_true_node
2054e4b17023SJohn Marino 		: or_var_with_comparison (inner2, false, code2, op2a, op2b));
2055e4b17023SJohn Marino       else if (inner2 == false_test_var)
2056e4b17023SJohn Marino 	return (is_or
2057e4b17023SJohn Marino 		? boolean_true_node
2058e4b17023SJohn Marino 		: or_var_with_comparison (inner1, false, code2, op2a, op2b));
2059e4b17023SJohn Marino 
2060e4b17023SJohn Marino       /* Next, redistribute/reassociate the OR across the inner tests.
2061e4b17023SJohn Marino 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
2062e4b17023SJohn Marino       if (TREE_CODE (inner1) == SSA_NAME
2063e4b17023SJohn Marino 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
2064e4b17023SJohn Marino 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
2065e4b17023SJohn Marino 	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
2066e4b17023SJohn Marino 					     gimple_assign_rhs1 (s),
2067e4b17023SJohn Marino 					     gimple_assign_rhs2 (s),
2068e4b17023SJohn Marino 					     code2, op2a, op2b)))
2069e4b17023SJohn Marino 	{
2070e4b17023SJohn Marino 	  /* Handle the OR case, where we are reassociating:
2071e4b17023SJohn Marino 	     (inner1 OR inner2) OR (op2a code2 op2b)
2072e4b17023SJohn Marino 	     => (t OR inner2)
2073e4b17023SJohn Marino 	     If the partial result t is a constant, we win.  Otherwise
2074e4b17023SJohn Marino 	     continue on to try reassociating with the other inner test.  */
2075e4b17023SJohn Marino 	  if (is_or)
2076e4b17023SJohn Marino 	    {
2077e4b17023SJohn Marino 	      if (integer_onep (t))
2078e4b17023SJohn Marino 		return boolean_true_node;
2079e4b17023SJohn Marino 	      else if (integer_zerop (t))
2080e4b17023SJohn Marino 		return inner2;
2081e4b17023SJohn Marino 	    }
2082e4b17023SJohn Marino 
2083e4b17023SJohn Marino 	  /* Handle the AND case, where we are redistributing:
2084e4b17023SJohn Marino 	     (inner1 AND inner2) OR (op2a code2 op2b)
2085e4b17023SJohn Marino 	     => (t AND (inner2 OR (op2a code op2b)))  */
2086e4b17023SJohn Marino 	  else if (integer_zerop (t))
2087e4b17023SJohn Marino 	    return boolean_false_node;
2088e4b17023SJohn Marino 
2089e4b17023SJohn Marino 	  /* Save partial result for later.  */
2090e4b17023SJohn Marino 	  partial = t;
2091e4b17023SJohn Marino 	}
2092e4b17023SJohn Marino 
2093e4b17023SJohn Marino       /* Compute the second partial result, (inner2 OR (op2a code op2b)) */
2094e4b17023SJohn Marino       if (TREE_CODE (inner2) == SSA_NAME
2095e4b17023SJohn Marino 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
2096e4b17023SJohn Marino 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
2097e4b17023SJohn Marino 	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
2098e4b17023SJohn Marino 					     gimple_assign_rhs1 (s),
2099e4b17023SJohn Marino 					     gimple_assign_rhs2 (s),
2100e4b17023SJohn Marino 					     code2, op2a, op2b)))
2101e4b17023SJohn Marino 	{
2102e4b17023SJohn Marino 	  /* Handle the OR case, where we are reassociating:
2103e4b17023SJohn Marino 	     (inner1 OR inner2) OR (op2a code2 op2b)
2104e4b17023SJohn Marino 	     => (inner1 OR t)
2105e4b17023SJohn Marino 	     => (t OR partial)  */
2106e4b17023SJohn Marino 	  if (is_or)
2107e4b17023SJohn Marino 	    {
2108e4b17023SJohn Marino 	      if (integer_zerop (t))
2109e4b17023SJohn Marino 		return inner1;
2110e4b17023SJohn Marino 	      else if (integer_onep (t))
2111e4b17023SJohn Marino 		return boolean_true_node;
2112e4b17023SJohn Marino 	      /* If both are the same, we can apply the identity
2113e4b17023SJohn Marino 		 (x OR x) == x.  */
2114e4b17023SJohn Marino 	      else if (partial && same_bool_result_p (t, partial))
2115e4b17023SJohn Marino 		return t;
2116e4b17023SJohn Marino 	    }
2117e4b17023SJohn Marino 
2118e4b17023SJohn Marino 	  /* Handle the AND case, where we are redistributing:
2119e4b17023SJohn Marino 	     (inner1 AND inner2) OR (op2a code2 op2b)
2120e4b17023SJohn Marino 	     => (t AND (inner1 OR (op2a code2 op2b)))
2121e4b17023SJohn Marino 	     => (t AND partial)  */
2122e4b17023SJohn Marino 	  else
2123e4b17023SJohn Marino 	    {
2124e4b17023SJohn Marino 	      if (integer_zerop (t))
2125e4b17023SJohn Marino 		return boolean_false_node;
2126e4b17023SJohn Marino 	      else if (partial)
2127e4b17023SJohn Marino 		{
2128e4b17023SJohn Marino 		  /* We already got a simplification for the other
2129e4b17023SJohn Marino 		     operand to the redistributed AND expression.  The
2130e4b17023SJohn Marino 		     interesting case is when at least one is true.
2131e4b17023SJohn Marino 		     Or, if both are the same, we can apply the identity
2132e4b17023SJohn Marino 		     (x AND x) == x.  */
2133e4b17023SJohn Marino 		  if (integer_onep (partial))
2134e4b17023SJohn Marino 		    return t;
2135e4b17023SJohn Marino 		  else if (integer_onep (t))
2136e4b17023SJohn Marino 		    return partial;
2137e4b17023SJohn Marino 		  else if (same_bool_result_p (t, partial))
2138e4b17023SJohn Marino 		    return t;
2139e4b17023SJohn Marino 		}
2140e4b17023SJohn Marino 	    }
2141e4b17023SJohn Marino 	}
2142e4b17023SJohn Marino     }
2143e4b17023SJohn Marino   return NULL_TREE;
2144e4b17023SJohn Marino }
2145e4b17023SJohn Marino 
2146e4b17023SJohn Marino /* Try to simplify the OR of two comparisons defined by
2147e4b17023SJohn Marino    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
2148e4b17023SJohn Marino    If this can be done without constructing an intermediate value,
2149e4b17023SJohn Marino    return the resulting tree; otherwise NULL_TREE is returned.
2150e4b17023SJohn Marino    This function is deliberately asymmetric as it recurses on SSA_DEFs
2151e4b17023SJohn Marino    in the first comparison but not the second.  */
2152e4b17023SJohn Marino 
2153e4b17023SJohn Marino static tree
or_comparisons_1(enum tree_code code1,tree op1a,tree op1b,enum tree_code code2,tree op2a,tree op2b)2154e4b17023SJohn Marino or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
2155e4b17023SJohn Marino 		  enum tree_code code2, tree op2a, tree op2b)
2156e4b17023SJohn Marino {
2157e4b17023SJohn Marino   /* First check for ((x CODE1 y) OR (x CODE2 y)).  */
2158e4b17023SJohn Marino   if (operand_equal_p (op1a, op2a, 0)
2159e4b17023SJohn Marino       && operand_equal_p (op1b, op2b, 0))
2160e4b17023SJohn Marino     {
2161e4b17023SJohn Marino       /* Result will be either NULL_TREE, or a combined comparison.  */
2162e4b17023SJohn Marino       tree t = combine_comparisons (UNKNOWN_LOCATION,
2163e4b17023SJohn Marino 				    TRUTH_ORIF_EXPR, code1, code2,
2164e4b17023SJohn Marino 				    boolean_type_node, op1a, op1b);
2165e4b17023SJohn Marino       if (t)
2166e4b17023SJohn Marino 	return t;
2167e4b17023SJohn Marino     }
2168e4b17023SJohn Marino 
2169e4b17023SJohn Marino   /* Likewise the swapped case of the above.  */
2170e4b17023SJohn Marino   if (operand_equal_p (op1a, op2b, 0)
2171e4b17023SJohn Marino       && operand_equal_p (op1b, op2a, 0))
2172e4b17023SJohn Marino     {
2173e4b17023SJohn Marino       /* Result will be either NULL_TREE, or a combined comparison.  */
2174e4b17023SJohn Marino       tree t = combine_comparisons (UNKNOWN_LOCATION,
2175e4b17023SJohn Marino 				    TRUTH_ORIF_EXPR, code1,
2176e4b17023SJohn Marino 				    swap_tree_comparison (code2),
2177e4b17023SJohn Marino 				    boolean_type_node, op1a, op1b);
2178e4b17023SJohn Marino       if (t)
2179e4b17023SJohn Marino 	return t;
2180e4b17023SJohn Marino     }
2181e4b17023SJohn Marino 
2182e4b17023SJohn Marino   /* If both comparisons are of the same value against constants, we might
2183e4b17023SJohn Marino      be able to merge them.  */
2184e4b17023SJohn Marino   if (operand_equal_p (op1a, op2a, 0)
2185e4b17023SJohn Marino       && TREE_CODE (op1b) == INTEGER_CST
2186e4b17023SJohn Marino       && TREE_CODE (op2b) == INTEGER_CST)
2187e4b17023SJohn Marino     {
2188e4b17023SJohn Marino       int cmp = tree_int_cst_compare (op1b, op2b);
2189e4b17023SJohn Marino 
2190e4b17023SJohn Marino       /* If we have (op1a != op1b), we should either be able to
2191e4b17023SJohn Marino 	 return that or TRUE, depending on whether the constant op1b
2192e4b17023SJohn Marino 	 also satisfies the other comparison against op2b.  */
2193e4b17023SJohn Marino       if (code1 == NE_EXPR)
2194e4b17023SJohn Marino 	{
2195e4b17023SJohn Marino 	  bool done = true;
2196e4b17023SJohn Marino 	  bool val;
2197e4b17023SJohn Marino 	  switch (code2)
2198e4b17023SJohn Marino 	    {
2199e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
2200e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
2201e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp < 0); break;
2202e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp > 0); break;
2203e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp <= 0); break;
2204e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp >= 0); break;
2205e4b17023SJohn Marino 	    default: done = false;
2206e4b17023SJohn Marino 	    }
2207e4b17023SJohn Marino 	  if (done)
2208e4b17023SJohn Marino 	    {
2209e4b17023SJohn Marino 	      if (val)
2210e4b17023SJohn Marino 		return boolean_true_node;
2211e4b17023SJohn Marino 	      else
2212e4b17023SJohn Marino 		return fold_build2 (code1, boolean_type_node, op1a, op1b);
2213e4b17023SJohn Marino 	    }
2214e4b17023SJohn Marino 	}
2215e4b17023SJohn Marino       /* Likewise if the second comparison is a != comparison.  */
2216e4b17023SJohn Marino       else if (code2 == NE_EXPR)
2217e4b17023SJohn Marino 	{
2218e4b17023SJohn Marino 	  bool done = true;
2219e4b17023SJohn Marino 	  bool val;
2220e4b17023SJohn Marino 	  switch (code1)
2221e4b17023SJohn Marino 	    {
2222e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
2223e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
2224e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp > 0); break;
2225e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp < 0); break;
2226e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp >= 0); break;
2227e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp <= 0); break;
2228e4b17023SJohn Marino 	    default: done = false;
2229e4b17023SJohn Marino 	    }
2230e4b17023SJohn Marino 	  if (done)
2231e4b17023SJohn Marino 	    {
2232e4b17023SJohn Marino 	      if (val)
2233e4b17023SJohn Marino 		return boolean_true_node;
2234e4b17023SJohn Marino 	      else
2235e4b17023SJohn Marino 		return fold_build2 (code2, boolean_type_node, op2a, op2b);
2236e4b17023SJohn Marino 	    }
2237e4b17023SJohn Marino 	}
2238e4b17023SJohn Marino 
2239e4b17023SJohn Marino       /* See if an equality test is redundant with the other comparison.  */
2240e4b17023SJohn Marino       else if (code1 == EQ_EXPR)
2241e4b17023SJohn Marino 	{
2242e4b17023SJohn Marino 	  bool val;
2243e4b17023SJohn Marino 	  switch (code2)
2244e4b17023SJohn Marino 	    {
2245e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
2246e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
2247e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp < 0); break;
2248e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp > 0); break;
2249e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp <= 0); break;
2250e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp >= 0); break;
2251e4b17023SJohn Marino 	    default:
2252e4b17023SJohn Marino 	      val = false;
2253e4b17023SJohn Marino 	    }
2254e4b17023SJohn Marino 	  if (val)
2255e4b17023SJohn Marino 	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
2256e4b17023SJohn Marino 	}
2257e4b17023SJohn Marino       else if (code2 == EQ_EXPR)
2258e4b17023SJohn Marino 	{
2259e4b17023SJohn Marino 	  bool val;
2260e4b17023SJohn Marino 	  switch (code1)
2261e4b17023SJohn Marino 	    {
2262e4b17023SJohn Marino 	    case EQ_EXPR: val = (cmp == 0); break;
2263e4b17023SJohn Marino 	    case NE_EXPR: val = (cmp != 0); break;
2264e4b17023SJohn Marino 	    case LT_EXPR: val = (cmp > 0); break;
2265e4b17023SJohn Marino 	    case GT_EXPR: val = (cmp < 0); break;
2266e4b17023SJohn Marino 	    case LE_EXPR: val = (cmp >= 0); break;
2267e4b17023SJohn Marino 	    case GE_EXPR: val = (cmp <= 0); break;
2268e4b17023SJohn Marino 	    default:
2269e4b17023SJohn Marino 	      val = false;
2270e4b17023SJohn Marino 	    }
2271e4b17023SJohn Marino 	  if (val)
2272e4b17023SJohn Marino 	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
2273e4b17023SJohn Marino 	}
2274e4b17023SJohn Marino 
2275e4b17023SJohn Marino       /* Chose the less restrictive of two < or <= comparisons.  */
2276e4b17023SJohn Marino       else if ((code1 == LT_EXPR || code1 == LE_EXPR)
2277e4b17023SJohn Marino 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
2278e4b17023SJohn Marino 	{
2279e4b17023SJohn Marino 	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
2280e4b17023SJohn Marino 	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
2281e4b17023SJohn Marino 	  else
2282e4b17023SJohn Marino 	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
2283e4b17023SJohn Marino 	}
2284e4b17023SJohn Marino 
2285e4b17023SJohn Marino       /* Likewise chose the less restrictive of two > or >= comparisons.  */
2286e4b17023SJohn Marino       else if ((code1 == GT_EXPR || code1 == GE_EXPR)
2287e4b17023SJohn Marino 	       && (code2 == GT_EXPR || code2 == GE_EXPR))
2288e4b17023SJohn Marino 	{
2289e4b17023SJohn Marino 	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
2290e4b17023SJohn Marino 	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
2291e4b17023SJohn Marino 	  else
2292e4b17023SJohn Marino 	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
2293e4b17023SJohn Marino 	}
2294e4b17023SJohn Marino 
2295e4b17023SJohn Marino       /* Check for singleton ranges.  */
2296e4b17023SJohn Marino       else if (cmp == 0
2297e4b17023SJohn Marino 	       && ((code1 == LT_EXPR && code2 == GT_EXPR)
2298e4b17023SJohn Marino 		   || (code1 == GT_EXPR && code2 == LT_EXPR)))
2299e4b17023SJohn Marino 	return fold_build2 (NE_EXPR, boolean_type_node, op1a, op2b);
2300e4b17023SJohn Marino 
2301e4b17023SJohn Marino       /* Check for less/greater pairs that don't restrict the range at all.  */
2302e4b17023SJohn Marino       else if (cmp >= 0
2303e4b17023SJohn Marino 	       && (code1 == LT_EXPR || code1 == LE_EXPR)
2304e4b17023SJohn Marino 	       && (code2 == GT_EXPR || code2 == GE_EXPR))
2305e4b17023SJohn Marino 	return boolean_true_node;
2306e4b17023SJohn Marino       else if (cmp <= 0
2307e4b17023SJohn Marino 	       && (code1 == GT_EXPR || code1 == GE_EXPR)
2308e4b17023SJohn Marino 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
2309e4b17023SJohn Marino 	return boolean_true_node;
2310e4b17023SJohn Marino     }
2311e4b17023SJohn Marino 
2312e4b17023SJohn Marino   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
2313e4b17023SJohn Marino      NAME's definition is a truth value.  See if there are any simplifications
2314e4b17023SJohn Marino      that can be done against the NAME's definition.  */
2315e4b17023SJohn Marino   if (TREE_CODE (op1a) == SSA_NAME
2316e4b17023SJohn Marino       && (code1 == NE_EXPR || code1 == EQ_EXPR)
2317e4b17023SJohn Marino       && (integer_zerop (op1b) || integer_onep (op1b)))
2318e4b17023SJohn Marino     {
2319e4b17023SJohn Marino       bool invert = ((code1 == EQ_EXPR && integer_zerop (op1b))
2320e4b17023SJohn Marino 		     || (code1 == NE_EXPR && integer_onep (op1b)));
2321e4b17023SJohn Marino       gimple stmt = SSA_NAME_DEF_STMT (op1a);
2322e4b17023SJohn Marino       switch (gimple_code (stmt))
2323e4b17023SJohn Marino 	{
2324e4b17023SJohn Marino 	case GIMPLE_ASSIGN:
2325e4b17023SJohn Marino 	  /* Try to simplify by copy-propagating the definition.  */
2326e4b17023SJohn Marino 	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
2327e4b17023SJohn Marino 
2328e4b17023SJohn Marino 	case GIMPLE_PHI:
2329e4b17023SJohn Marino 	  /* If every argument to the PHI produces the same result when
2330e4b17023SJohn Marino 	     ORed with the second comparison, we win.
2331e4b17023SJohn Marino 	     Do not do this unless the type is bool since we need a bool
2332e4b17023SJohn Marino 	     result here anyway.  */
2333e4b17023SJohn Marino 	  if (TREE_CODE (TREE_TYPE (op1a)) == BOOLEAN_TYPE)
2334e4b17023SJohn Marino 	    {
2335e4b17023SJohn Marino 	      tree result = NULL_TREE;
2336e4b17023SJohn Marino 	      unsigned i;
2337e4b17023SJohn Marino 	      for (i = 0; i < gimple_phi_num_args (stmt); i++)
2338e4b17023SJohn Marino 		{
2339e4b17023SJohn Marino 		  tree arg = gimple_phi_arg_def (stmt, i);
2340e4b17023SJohn Marino 
2341e4b17023SJohn Marino 		  /* If this PHI has itself as an argument, ignore it.
2342e4b17023SJohn Marino 		     If all the other args produce the same result,
2343e4b17023SJohn Marino 		     we're still OK.  */
2344e4b17023SJohn Marino 		  if (arg == gimple_phi_result (stmt))
2345e4b17023SJohn Marino 		    continue;
2346e4b17023SJohn Marino 		  else if (TREE_CODE (arg) == INTEGER_CST)
2347e4b17023SJohn Marino 		    {
2348e4b17023SJohn Marino 		      if (invert ? integer_zerop (arg) : integer_nonzerop (arg))
2349e4b17023SJohn Marino 			{
2350e4b17023SJohn Marino 			  if (!result)
2351e4b17023SJohn Marino 			    result = boolean_true_node;
2352e4b17023SJohn Marino 			  else if (!integer_onep (result))
2353e4b17023SJohn Marino 			    return NULL_TREE;
2354e4b17023SJohn Marino 			}
2355e4b17023SJohn Marino 		      else if (!result)
2356e4b17023SJohn Marino 			result = fold_build2 (code2, boolean_type_node,
2357e4b17023SJohn Marino 					      op2a, op2b);
2358e4b17023SJohn Marino 		      else if (!same_bool_comparison_p (result,
2359e4b17023SJohn Marino 							code2, op2a, op2b))
2360e4b17023SJohn Marino 			return NULL_TREE;
2361e4b17023SJohn Marino 		    }
2362e4b17023SJohn Marino 		  else if (TREE_CODE (arg) == SSA_NAME
2363e4b17023SJohn Marino 			   && !SSA_NAME_IS_DEFAULT_DEF (arg))
2364e4b17023SJohn Marino 		    {
2365e4b17023SJohn Marino 		      tree temp;
2366e4b17023SJohn Marino 		      gimple def_stmt = SSA_NAME_DEF_STMT (arg);
2367e4b17023SJohn Marino 		      /* In simple cases we can look through PHI nodes,
2368e4b17023SJohn Marino 			 but we have to be careful with loops.
2369e4b17023SJohn Marino 			 See PR49073.  */
2370e4b17023SJohn Marino 		      if (! dom_info_available_p (CDI_DOMINATORS)
2371e4b17023SJohn Marino 			  || gimple_bb (def_stmt) == gimple_bb (stmt)
2372e4b17023SJohn Marino 			  || dominated_by_p (CDI_DOMINATORS,
2373e4b17023SJohn Marino 					     gimple_bb (def_stmt),
2374e4b17023SJohn Marino 					     gimple_bb (stmt)))
2375e4b17023SJohn Marino 			return NULL_TREE;
2376e4b17023SJohn Marino 		      temp = or_var_with_comparison (arg, invert, code2,
2377e4b17023SJohn Marino 						     op2a, op2b);
2378e4b17023SJohn Marino 		      if (!temp)
2379e4b17023SJohn Marino 			return NULL_TREE;
2380e4b17023SJohn Marino 		      else if (!result)
2381e4b17023SJohn Marino 			result = temp;
2382e4b17023SJohn Marino 		      else if (!same_bool_result_p (result, temp))
2383e4b17023SJohn Marino 			return NULL_TREE;
2384e4b17023SJohn Marino 		    }
2385e4b17023SJohn Marino 		  else
2386e4b17023SJohn Marino 		    return NULL_TREE;
2387e4b17023SJohn Marino 		}
2388e4b17023SJohn Marino 	      return result;
2389e4b17023SJohn Marino 	    }
2390e4b17023SJohn Marino 
2391e4b17023SJohn Marino 	default:
2392e4b17023SJohn Marino 	  break;
2393e4b17023SJohn Marino 	}
2394e4b17023SJohn Marino     }
2395e4b17023SJohn Marino   return NULL_TREE;
2396e4b17023SJohn Marino }
2397e4b17023SJohn Marino 
2398e4b17023SJohn Marino /* Try to simplify the OR of two comparisons, specified by
2399e4b17023SJohn Marino    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
2400e4b17023SJohn Marino    If this can be simplified to a single expression (without requiring
2401e4b17023SJohn Marino    introducing more SSA variables to hold intermediate values),
2402e4b17023SJohn Marino    return the resulting tree.  Otherwise return NULL_TREE.
2403e4b17023SJohn Marino    If the result expression is non-null, it has boolean type.  */
2404e4b17023SJohn Marino 
2405e4b17023SJohn Marino tree
maybe_fold_or_comparisons(enum tree_code code1,tree op1a,tree op1b,enum tree_code code2,tree op2a,tree op2b)2406e4b17023SJohn Marino maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
2407e4b17023SJohn Marino 			   enum tree_code code2, tree op2a, tree op2b)
2408e4b17023SJohn Marino {
2409e4b17023SJohn Marino   tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
2410e4b17023SJohn Marino   if (t)
2411e4b17023SJohn Marino     return t;
2412e4b17023SJohn Marino   else
2413e4b17023SJohn Marino     return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
2414e4b17023SJohn Marino }
2415e4b17023SJohn Marino 
2416e4b17023SJohn Marino 
2417e4b17023SJohn Marino /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
2418e4b17023SJohn Marino 
2419e4b17023SJohn Marino    Either NULL_TREE, a simplified but non-constant or a constant
2420e4b17023SJohn Marino    is returned.
2421e4b17023SJohn Marino 
2422e4b17023SJohn Marino    ???  This should go into a gimple-fold-inline.h file to be eventually
2423e4b17023SJohn Marino    privatized with the single valueize function used in the various TUs
2424e4b17023SJohn Marino    to avoid the indirect function call overhead.  */
2425e4b17023SJohn Marino 
2426e4b17023SJohn Marino tree
gimple_fold_stmt_to_constant_1(gimple stmt,tree (* valueize)(tree))2427e4b17023SJohn Marino gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
2428e4b17023SJohn Marino {
2429e4b17023SJohn Marino   location_t loc = gimple_location (stmt);
2430e4b17023SJohn Marino   switch (gimple_code (stmt))
2431e4b17023SJohn Marino     {
2432e4b17023SJohn Marino     case GIMPLE_ASSIGN:
2433e4b17023SJohn Marino       {
2434e4b17023SJohn Marino         enum tree_code subcode = gimple_assign_rhs_code (stmt);
2435e4b17023SJohn Marino 
2436e4b17023SJohn Marino         switch (get_gimple_rhs_class (subcode))
2437e4b17023SJohn Marino           {
2438e4b17023SJohn Marino           case GIMPLE_SINGLE_RHS:
2439e4b17023SJohn Marino             {
2440e4b17023SJohn Marino               tree rhs = gimple_assign_rhs1 (stmt);
2441e4b17023SJohn Marino               enum tree_code_class kind = TREE_CODE_CLASS (subcode);
2442e4b17023SJohn Marino 
2443e4b17023SJohn Marino               if (TREE_CODE (rhs) == SSA_NAME)
2444e4b17023SJohn Marino                 {
2445e4b17023SJohn Marino                   /* If the RHS is an SSA_NAME, return its known constant value,
2446e4b17023SJohn Marino                      if any.  */
2447e4b17023SJohn Marino                   return (*valueize) (rhs);
2448e4b17023SJohn Marino                 }
2449e4b17023SJohn Marino 	      /* Handle propagating invariant addresses into address
2450e4b17023SJohn Marino 		 operations.  */
2451e4b17023SJohn Marino 	      else if (TREE_CODE (rhs) == ADDR_EXPR
2452e4b17023SJohn Marino 		       && !is_gimple_min_invariant (rhs))
2453e4b17023SJohn Marino 		{
2454e4b17023SJohn Marino 		  HOST_WIDE_INT offset;
2455e4b17023SJohn Marino 		  tree base;
2456e4b17023SJohn Marino 		  base = get_addr_base_and_unit_offset_1 (TREE_OPERAND (rhs, 0),
2457e4b17023SJohn Marino 							  &offset,
2458e4b17023SJohn Marino 							  valueize);
2459e4b17023SJohn Marino 		  if (base
2460e4b17023SJohn Marino 		      && (CONSTANT_CLASS_P (base)
2461e4b17023SJohn Marino 			  || decl_address_invariant_p (base)))
2462e4b17023SJohn Marino 		    return build_invariant_address (TREE_TYPE (rhs),
2463e4b17023SJohn Marino 						    base, offset);
2464e4b17023SJohn Marino 		}
2465e4b17023SJohn Marino 	      else if (TREE_CODE (rhs) == CONSTRUCTOR
2466e4b17023SJohn Marino 		       && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE
2467e4b17023SJohn Marino 		       && (CONSTRUCTOR_NELTS (rhs)
2468e4b17023SJohn Marino 			   == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs))))
2469e4b17023SJohn Marino 		{
2470e4b17023SJohn Marino 		  unsigned i;
2471e4b17023SJohn Marino 		  tree val, list;
2472e4b17023SJohn Marino 
2473e4b17023SJohn Marino 		  list = NULL_TREE;
2474e4b17023SJohn Marino 		  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val)
2475e4b17023SJohn Marino 		    {
2476e4b17023SJohn Marino 		      val = (*valueize) (val);
2477e4b17023SJohn Marino 		      if (TREE_CODE (val) == INTEGER_CST
2478e4b17023SJohn Marino 			  || TREE_CODE (val) == REAL_CST
2479e4b17023SJohn Marino 			  || TREE_CODE (val) == FIXED_CST)
2480e4b17023SJohn Marino 			list = tree_cons (NULL_TREE, val, list);
2481e4b17023SJohn Marino 		      else
2482e4b17023SJohn Marino 			return NULL_TREE;
2483e4b17023SJohn Marino 		    }
2484e4b17023SJohn Marino 
2485e4b17023SJohn Marino 		  return build_vector (TREE_TYPE (rhs), nreverse (list));
2486e4b17023SJohn Marino 		}
2487e4b17023SJohn Marino 
2488e4b17023SJohn Marino               if (kind == tcc_reference)
2489e4b17023SJohn Marino 		{
2490e4b17023SJohn Marino 		  if ((TREE_CODE (rhs) == VIEW_CONVERT_EXPR
2491e4b17023SJohn Marino 		       || TREE_CODE (rhs) == REALPART_EXPR
2492e4b17023SJohn Marino 		       || TREE_CODE (rhs) == IMAGPART_EXPR)
2493e4b17023SJohn Marino 		      && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
2494e4b17023SJohn Marino 		    {
2495e4b17023SJohn Marino 		      tree val = (*valueize) (TREE_OPERAND (rhs, 0));
2496e4b17023SJohn Marino 		      return fold_unary_loc (EXPR_LOCATION (rhs),
2497e4b17023SJohn Marino 					     TREE_CODE (rhs),
2498e4b17023SJohn Marino 					     TREE_TYPE (rhs), val);
2499e4b17023SJohn Marino 		    }
2500e4b17023SJohn Marino 		  else if (TREE_CODE (rhs) == BIT_FIELD_REF
2501e4b17023SJohn Marino 			   && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
2502e4b17023SJohn Marino 		    {
2503e4b17023SJohn Marino 		      tree val = (*valueize) (TREE_OPERAND (rhs, 0));
2504e4b17023SJohn Marino 		      return fold_ternary_loc (EXPR_LOCATION (rhs),
2505e4b17023SJohn Marino 					       TREE_CODE (rhs),
2506e4b17023SJohn Marino 					       TREE_TYPE (rhs), val,
2507e4b17023SJohn Marino 					       TREE_OPERAND (rhs, 1),
2508e4b17023SJohn Marino 					       TREE_OPERAND (rhs, 2));
2509e4b17023SJohn Marino 		    }
2510e4b17023SJohn Marino 		  else if (TREE_CODE (rhs) == MEM_REF
2511e4b17023SJohn Marino 			   && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
2512e4b17023SJohn Marino 		    {
2513e4b17023SJohn Marino 		      tree val = (*valueize) (TREE_OPERAND (rhs, 0));
2514e4b17023SJohn Marino 		      if (TREE_CODE (val) == ADDR_EXPR
2515e4b17023SJohn Marino 			  && is_gimple_min_invariant (val))
2516e4b17023SJohn Marino 			{
2517e4b17023SJohn Marino 			  tree tem = fold_build2 (MEM_REF, TREE_TYPE (rhs),
2518e4b17023SJohn Marino 						  unshare_expr (val),
2519e4b17023SJohn Marino 						  TREE_OPERAND (rhs, 1));
2520e4b17023SJohn Marino 			  if (tem)
2521e4b17023SJohn Marino 			    rhs = tem;
2522e4b17023SJohn Marino 			}
2523e4b17023SJohn Marino 		    }
2524e4b17023SJohn Marino 		  return fold_const_aggregate_ref_1 (rhs, valueize);
2525e4b17023SJohn Marino 		}
2526e4b17023SJohn Marino               else if (kind == tcc_declaration)
2527e4b17023SJohn Marino                 return get_symbol_constant_value (rhs);
2528e4b17023SJohn Marino               return rhs;
2529e4b17023SJohn Marino             }
2530e4b17023SJohn Marino 
2531e4b17023SJohn Marino           case GIMPLE_UNARY_RHS:
2532e4b17023SJohn Marino             {
2533e4b17023SJohn Marino               /* Handle unary operators that can appear in GIMPLE form.
2534e4b17023SJohn Marino                  Note that we know the single operand must be a constant,
2535e4b17023SJohn Marino                  so this should almost always return a simplified RHS.  */
2536e4b17023SJohn Marino 	      tree lhs = gimple_assign_lhs (stmt);
2537e4b17023SJohn Marino               tree op0 = (*valueize) (gimple_assign_rhs1 (stmt));
2538e4b17023SJohn Marino 
2539e4b17023SJohn Marino 	      /* Conversions are useless for CCP purposes if they are
2540e4b17023SJohn Marino 		 value-preserving.  Thus the restrictions that
2541e4b17023SJohn Marino 		 useless_type_conversion_p places for restrict qualification
2542e4b17023SJohn Marino 		 of pointer types should not apply here.
2543e4b17023SJohn Marino 		 Substitution later will only substitute to allowed places.  */
2544e4b17023SJohn Marino 	      if (CONVERT_EXPR_CODE_P (subcode)
2545e4b17023SJohn Marino 		  && POINTER_TYPE_P (TREE_TYPE (lhs))
2546e4b17023SJohn Marino 		  && POINTER_TYPE_P (TREE_TYPE (op0))
2547e4b17023SJohn Marino 		  && TYPE_ADDR_SPACE (TREE_TYPE (lhs))
2548e4b17023SJohn Marino 		     == TYPE_ADDR_SPACE (TREE_TYPE (op0))
2549e4b17023SJohn Marino 		  && TYPE_MODE (TREE_TYPE (lhs))
2550e4b17023SJohn Marino 		     == TYPE_MODE (TREE_TYPE (op0)))
2551e4b17023SJohn Marino 		return op0;
2552e4b17023SJohn Marino 
2553e4b17023SJohn Marino               return
2554e4b17023SJohn Marino 		fold_unary_ignore_overflow_loc (loc, subcode,
2555e4b17023SJohn Marino 						gimple_expr_type (stmt), op0);
2556e4b17023SJohn Marino             }
2557e4b17023SJohn Marino 
2558e4b17023SJohn Marino           case GIMPLE_BINARY_RHS:
2559e4b17023SJohn Marino             {
2560e4b17023SJohn Marino               /* Handle binary operators that can appear in GIMPLE form.  */
2561e4b17023SJohn Marino               tree op0 = (*valueize) (gimple_assign_rhs1 (stmt));
2562e4b17023SJohn Marino               tree op1 = (*valueize) (gimple_assign_rhs2 (stmt));
2563e4b17023SJohn Marino 
2564e4b17023SJohn Marino 	      /* Translate &x + CST into an invariant form suitable for
2565e4b17023SJohn Marino 	         further propagation.  */
2566e4b17023SJohn Marino 	      if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
2567e4b17023SJohn Marino 		  && TREE_CODE (op0) == ADDR_EXPR
2568e4b17023SJohn Marino 		  && TREE_CODE (op1) == INTEGER_CST)
2569e4b17023SJohn Marino 		{
2570e4b17023SJohn Marino 		  tree off = fold_convert (ptr_type_node, op1);
2571e4b17023SJohn Marino 		  return build_fold_addr_expr_loc
2572e4b17023SJohn Marino 			   (loc,
2573e4b17023SJohn Marino 			    fold_build2 (MEM_REF,
2574e4b17023SJohn Marino 					 TREE_TYPE (TREE_TYPE (op0)),
2575e4b17023SJohn Marino 					 unshare_expr (op0), off));
2576e4b17023SJohn Marino 		}
2577e4b17023SJohn Marino 
2578e4b17023SJohn Marino               return fold_binary_loc (loc, subcode,
2579e4b17023SJohn Marino 				      gimple_expr_type (stmt), op0, op1);
2580e4b17023SJohn Marino             }
2581e4b17023SJohn Marino 
2582e4b17023SJohn Marino           case GIMPLE_TERNARY_RHS:
2583e4b17023SJohn Marino             {
2584e4b17023SJohn Marino               /* Handle ternary operators that can appear in GIMPLE form.  */
2585e4b17023SJohn Marino               tree op0 = (*valueize) (gimple_assign_rhs1 (stmt));
2586e4b17023SJohn Marino               tree op1 = (*valueize) (gimple_assign_rhs2 (stmt));
2587e4b17023SJohn Marino               tree op2 = (*valueize) (gimple_assign_rhs3 (stmt));
2588e4b17023SJohn Marino 
2589e4b17023SJohn Marino 	      /* Fold embedded expressions in ternary codes.  */
2590e4b17023SJohn Marino 	      if ((subcode == COND_EXPR
2591e4b17023SJohn Marino 		   || subcode == VEC_COND_EXPR)
2592e4b17023SJohn Marino 		  && COMPARISON_CLASS_P (op0))
2593e4b17023SJohn Marino 		{
2594e4b17023SJohn Marino 		  tree op00 = (*valueize) (TREE_OPERAND (op0, 0));
2595e4b17023SJohn Marino 		  tree op01 = (*valueize) (TREE_OPERAND (op0, 1));
2596e4b17023SJohn Marino 		  tree tem = fold_binary_loc (loc, TREE_CODE (op0),
2597e4b17023SJohn Marino 					      TREE_TYPE (op0), op00, op01);
2598e4b17023SJohn Marino 		  if (tem)
2599e4b17023SJohn Marino 		    op0 = tem;
2600e4b17023SJohn Marino 		}
2601e4b17023SJohn Marino 
2602e4b17023SJohn Marino               return fold_ternary_loc (loc, subcode,
2603e4b17023SJohn Marino 				       gimple_expr_type (stmt), op0, op1, op2);
2604e4b17023SJohn Marino             }
2605e4b17023SJohn Marino 
2606e4b17023SJohn Marino           default:
2607e4b17023SJohn Marino             gcc_unreachable ();
2608e4b17023SJohn Marino           }
2609e4b17023SJohn Marino       }
2610e4b17023SJohn Marino 
2611e4b17023SJohn Marino     case GIMPLE_CALL:
2612e4b17023SJohn Marino       {
2613e4b17023SJohn Marino 	tree fn;
2614e4b17023SJohn Marino 
2615e4b17023SJohn Marino 	if (gimple_call_internal_p (stmt))
2616e4b17023SJohn Marino 	  /* No folding yet for these functions.  */
2617e4b17023SJohn Marino 	  return NULL_TREE;
2618e4b17023SJohn Marino 
2619e4b17023SJohn Marino 	fn = (*valueize) (gimple_call_fn (stmt));
2620e4b17023SJohn Marino 	if (TREE_CODE (fn) == ADDR_EXPR
2621e4b17023SJohn Marino 	    && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
2622e4b17023SJohn Marino 	    && DECL_BUILT_IN (TREE_OPERAND (fn, 0)))
2623e4b17023SJohn Marino 	  {
2624e4b17023SJohn Marino 	    tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt));
2625e4b17023SJohn Marino 	    tree call, retval;
2626e4b17023SJohn Marino 	    unsigned i;
2627e4b17023SJohn Marino 	    for (i = 0; i < gimple_call_num_args (stmt); ++i)
2628e4b17023SJohn Marino 	      args[i] = (*valueize) (gimple_call_arg (stmt, i));
2629e4b17023SJohn Marino 	    call = build_call_array_loc (loc,
2630e4b17023SJohn Marino 					 gimple_call_return_type (stmt),
2631e4b17023SJohn Marino 					 fn, gimple_call_num_args (stmt), args);
2632e4b17023SJohn Marino 	    retval = fold_call_expr (EXPR_LOCATION (call), call, false);
2633e4b17023SJohn Marino 	    if (retval)
2634e4b17023SJohn Marino 	      /* fold_call_expr wraps the result inside a NOP_EXPR.  */
2635e4b17023SJohn Marino 	      STRIP_NOPS (retval);
2636e4b17023SJohn Marino 	    return retval;
2637e4b17023SJohn Marino 	  }
2638e4b17023SJohn Marino 	return NULL_TREE;
2639e4b17023SJohn Marino       }
2640e4b17023SJohn Marino 
2641e4b17023SJohn Marino     default:
2642e4b17023SJohn Marino       return NULL_TREE;
2643e4b17023SJohn Marino     }
2644e4b17023SJohn Marino }
2645e4b17023SJohn Marino 
2646e4b17023SJohn Marino /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
2647e4b17023SJohn Marino    Returns NULL_TREE if folding to a constant is not possible, otherwise
2648e4b17023SJohn Marino    returns a constant according to is_gimple_min_invariant.  */
2649e4b17023SJohn Marino 
2650e4b17023SJohn Marino tree
gimple_fold_stmt_to_constant(gimple stmt,tree (* valueize)(tree))2651e4b17023SJohn Marino gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree))
2652e4b17023SJohn Marino {
2653e4b17023SJohn Marino   tree res = gimple_fold_stmt_to_constant_1 (stmt, valueize);
2654e4b17023SJohn Marino   if (res && is_gimple_min_invariant (res))
2655e4b17023SJohn Marino     return res;
2656e4b17023SJohn Marino   return NULL_TREE;
2657e4b17023SJohn Marino }
2658e4b17023SJohn Marino 
2659e4b17023SJohn Marino 
2660e4b17023SJohn Marino /* The following set of functions are supposed to fold references using
2661e4b17023SJohn Marino    their constant initializers.  */
2662e4b17023SJohn Marino 
2663e4b17023SJohn Marino static tree fold_ctor_reference (tree type, tree ctor,
2664e4b17023SJohn Marino 				 unsigned HOST_WIDE_INT offset,
2665e4b17023SJohn Marino 				 unsigned HOST_WIDE_INT size);
2666e4b17023SJohn Marino 
2667e4b17023SJohn Marino /* See if we can find constructor defining value of BASE.
2668e4b17023SJohn Marino    When we know the consructor with constant offset (such as
2669e4b17023SJohn Marino    base is array[40] and we do know constructor of array), then
2670e4b17023SJohn Marino    BIT_OFFSET is adjusted accordingly.
2671e4b17023SJohn Marino 
2672e4b17023SJohn Marino    As a special case, return error_mark_node when constructor
2673e4b17023SJohn Marino    is not explicitly available, but it is known to be zero
2674e4b17023SJohn Marino    such as 'static const int a;'.  */
2675e4b17023SJohn Marino static tree
get_base_constructor(tree base,HOST_WIDE_INT * bit_offset,tree (* valueize)(tree))2676e4b17023SJohn Marino get_base_constructor (tree base, HOST_WIDE_INT *bit_offset,
2677e4b17023SJohn Marino 		      tree (*valueize)(tree))
2678e4b17023SJohn Marino {
2679e4b17023SJohn Marino   HOST_WIDE_INT bit_offset2, size, max_size;
2680e4b17023SJohn Marino   if (TREE_CODE (base) == MEM_REF)
2681e4b17023SJohn Marino     {
2682e4b17023SJohn Marino       if (!integer_zerop (TREE_OPERAND (base, 1)))
2683e4b17023SJohn Marino 	{
2684e4b17023SJohn Marino 	  if (!host_integerp (TREE_OPERAND (base, 1), 0))
2685e4b17023SJohn Marino 	    return NULL_TREE;
2686e4b17023SJohn Marino 	  *bit_offset += (mem_ref_offset (base).low
2687e4b17023SJohn Marino 			  * BITS_PER_UNIT);
2688e4b17023SJohn Marino 	}
2689e4b17023SJohn Marino 
2690e4b17023SJohn Marino       if (valueize
2691e4b17023SJohn Marino 	  && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
2692e4b17023SJohn Marino 	base = valueize (TREE_OPERAND (base, 0));
2693e4b17023SJohn Marino       if (!base || TREE_CODE (base) != ADDR_EXPR)
2694e4b17023SJohn Marino         return NULL_TREE;
2695e4b17023SJohn Marino       base = TREE_OPERAND (base, 0);
2696e4b17023SJohn Marino     }
2697e4b17023SJohn Marino 
2698e4b17023SJohn Marino   /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
2699e4b17023SJohn Marino      DECL_INITIAL.  If BASE is a nested reference into another
2700e4b17023SJohn Marino      ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
2701e4b17023SJohn Marino      the inner reference.  */
2702e4b17023SJohn Marino   switch (TREE_CODE (base))
2703e4b17023SJohn Marino     {
2704e4b17023SJohn Marino     case VAR_DECL:
2705e4b17023SJohn Marino       if (!const_value_known_p (base))
2706e4b17023SJohn Marino 	return NULL_TREE;
2707e4b17023SJohn Marino 
2708e4b17023SJohn Marino       /* Fallthru.  */
2709e4b17023SJohn Marino     case CONST_DECL:
2710e4b17023SJohn Marino       if (!DECL_INITIAL (base)
2711e4b17023SJohn Marino 	  && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
2712e4b17023SJohn Marino         return error_mark_node;
2713e4b17023SJohn Marino       /* Do not return an error_mark_node DECL_INITIAL.  LTO uses this
2714e4b17023SJohn Marino          as special marker (_not_ zero ...) for its own purposes.  */
2715e4b17023SJohn Marino       if (DECL_INITIAL (base) == error_mark_node)
2716e4b17023SJohn Marino 	return NULL_TREE;
2717e4b17023SJohn Marino       return DECL_INITIAL (base);
2718e4b17023SJohn Marino 
2719e4b17023SJohn Marino     case ARRAY_REF:
2720e4b17023SJohn Marino     case COMPONENT_REF:
2721e4b17023SJohn Marino       base = get_ref_base_and_extent (base, &bit_offset2, &size, &max_size);
2722e4b17023SJohn Marino       if (max_size == -1 || size != max_size)
2723e4b17023SJohn Marino 	return NULL_TREE;
2724e4b17023SJohn Marino       *bit_offset +=  bit_offset2;
2725e4b17023SJohn Marino       return get_base_constructor (base, bit_offset, valueize);
2726e4b17023SJohn Marino 
2727e4b17023SJohn Marino     case STRING_CST:
2728e4b17023SJohn Marino     case CONSTRUCTOR:
2729e4b17023SJohn Marino       return base;
2730e4b17023SJohn Marino 
2731e4b17023SJohn Marino     default:
2732e4b17023SJohn Marino       return NULL_TREE;
2733e4b17023SJohn Marino     }
2734e4b17023SJohn Marino }
2735e4b17023SJohn Marino 
2736e4b17023SJohn Marino /* CTOR is STRING_CST.  Fold reference of type TYPE and size SIZE
2737e4b17023SJohn Marino    to the memory at bit OFFSET.
2738e4b17023SJohn Marino 
2739e4b17023SJohn Marino    We do only simple job of folding byte accesses.  */
2740e4b17023SJohn Marino 
2741e4b17023SJohn Marino static tree
fold_string_cst_ctor_reference(tree type,tree ctor,unsigned HOST_WIDE_INT offset,unsigned HOST_WIDE_INT size)2742e4b17023SJohn Marino fold_string_cst_ctor_reference (tree type, tree ctor,
2743e4b17023SJohn Marino 				unsigned HOST_WIDE_INT offset,
2744e4b17023SJohn Marino 				unsigned HOST_WIDE_INT size)
2745e4b17023SJohn Marino {
2746e4b17023SJohn Marino   if (INTEGRAL_TYPE_P (type)
2747e4b17023SJohn Marino       && (TYPE_MODE (type)
2748e4b17023SJohn Marino 	  == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
2749e4b17023SJohn Marino       && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
2750e4b17023SJohn Marino 	  == MODE_INT)
2751e4b17023SJohn Marino       && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
2752e4b17023SJohn Marino       && size == BITS_PER_UNIT
2753e4b17023SJohn Marino       && !(offset % BITS_PER_UNIT))
2754e4b17023SJohn Marino     {
2755e4b17023SJohn Marino       offset /= BITS_PER_UNIT;
2756e4b17023SJohn Marino       if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor))
2757e4b17023SJohn Marino 	return build_int_cst_type (type, (TREE_STRING_POINTER (ctor)
2758e4b17023SJohn Marino 				   [offset]));
2759e4b17023SJohn Marino       /* Folding
2760e4b17023SJohn Marino 	 const char a[20]="hello";
2761e4b17023SJohn Marino 	 return a[10];
2762e4b17023SJohn Marino 
2763e4b17023SJohn Marino 	 might lead to offset greater than string length.  In this case we
2764e4b17023SJohn Marino 	 know value is either initialized to 0 or out of bounds.  Return 0
2765e4b17023SJohn Marino 	 in both cases.  */
2766e4b17023SJohn Marino       return build_zero_cst (type);
2767e4b17023SJohn Marino     }
2768e4b17023SJohn Marino   return NULL_TREE;
2769e4b17023SJohn Marino }
2770e4b17023SJohn Marino 
2771e4b17023SJohn Marino /* CTOR is CONSTRUCTOR of an array type.  Fold reference of type TYPE and size
2772e4b17023SJohn Marino    SIZE to the memory at bit OFFSET.  */
2773e4b17023SJohn Marino 
2774e4b17023SJohn Marino static tree
fold_array_ctor_reference(tree type,tree ctor,unsigned HOST_WIDE_INT offset,unsigned HOST_WIDE_INT size)2775e4b17023SJohn Marino fold_array_ctor_reference (tree type, tree ctor,
2776e4b17023SJohn Marino 			   unsigned HOST_WIDE_INT offset,
2777e4b17023SJohn Marino 			   unsigned HOST_WIDE_INT size)
2778e4b17023SJohn Marino {
2779e4b17023SJohn Marino   unsigned HOST_WIDE_INT cnt;
2780e4b17023SJohn Marino   tree cfield, cval;
2781e4b17023SJohn Marino   double_int low_bound, elt_size;
2782e4b17023SJohn Marino   double_int index, max_index;
2783e4b17023SJohn Marino   double_int access_index;
2784e4b17023SJohn Marino   tree domain_type = NULL_TREE;
2785e4b17023SJohn Marino   HOST_WIDE_INT inner_offset;
2786e4b17023SJohn Marino 
2787e4b17023SJohn Marino   /* Compute low bound and elt size.  */
2788e4b17023SJohn Marino   if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE)
2789e4b17023SJohn Marino     domain_type = TYPE_DOMAIN (TREE_TYPE (ctor));
2790e4b17023SJohn Marino   if (domain_type && TYPE_MIN_VALUE (domain_type))
2791e4b17023SJohn Marino     {
2792e4b17023SJohn Marino       /* Static constructors for variably sized objects makes no sense.  */
2793e4b17023SJohn Marino       gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST);
2794e4b17023SJohn Marino       low_bound = tree_to_double_int (TYPE_MIN_VALUE (domain_type));
2795e4b17023SJohn Marino     }
2796e4b17023SJohn Marino   else
2797e4b17023SJohn Marino     low_bound = double_int_zero;
2798e4b17023SJohn Marino   /* Static constructors for variably sized objects makes no sense.  */
2799e4b17023SJohn Marino   gcc_assert (TREE_CODE(TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))))
2800e4b17023SJohn Marino 	      == INTEGER_CST);
2801e4b17023SJohn Marino   elt_size =
2802e4b17023SJohn Marino     tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))));
2803e4b17023SJohn Marino 
2804e4b17023SJohn Marino 
2805e4b17023SJohn Marino   /* We can handle only constantly sized accesses that are known to not
2806e4b17023SJohn Marino      be larger than size of array element.  */
2807e4b17023SJohn Marino   if (!TYPE_SIZE_UNIT (type)
2808e4b17023SJohn Marino       || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
2809e4b17023SJohn Marino       || double_int_cmp (elt_size,
2810e4b17023SJohn Marino 			 tree_to_double_int (TYPE_SIZE_UNIT (type)), 0) < 0)
2811e4b17023SJohn Marino     return NULL_TREE;
2812e4b17023SJohn Marino 
2813e4b17023SJohn Marino   /* Compute the array index we look for.  */
2814e4b17023SJohn Marino   access_index = double_int_udiv (uhwi_to_double_int (offset / BITS_PER_UNIT),
2815e4b17023SJohn Marino 				  elt_size, TRUNC_DIV_EXPR);
2816e4b17023SJohn Marino   access_index = double_int_add (access_index, low_bound);
2817e4b17023SJohn Marino 
2818e4b17023SJohn Marino   /* And offset within the access.  */
2819e4b17023SJohn Marino   inner_offset = offset % (double_int_to_uhwi (elt_size) * BITS_PER_UNIT);
2820e4b17023SJohn Marino 
2821e4b17023SJohn Marino   /* See if the array field is large enough to span whole access.  We do not
2822e4b17023SJohn Marino      care to fold accesses spanning multiple array indexes.  */
2823e4b17023SJohn Marino   if (inner_offset + size > double_int_to_uhwi (elt_size) * BITS_PER_UNIT)
2824e4b17023SJohn Marino     return NULL_TREE;
2825e4b17023SJohn Marino 
2826e4b17023SJohn Marino   index = double_int_sub (low_bound, double_int_one);
2827e4b17023SJohn Marino   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
2828e4b17023SJohn Marino     {
2829e4b17023SJohn Marino       /* Array constructor might explicitely set index, or specify range
2830e4b17023SJohn Marino 	 or leave index NULL meaning that it is next index after previous
2831e4b17023SJohn Marino 	 one.  */
2832e4b17023SJohn Marino       if (cfield)
2833e4b17023SJohn Marino 	{
2834e4b17023SJohn Marino 	  if (TREE_CODE (cfield) == INTEGER_CST)
2835e4b17023SJohn Marino 	    max_index = index = tree_to_double_int (cfield);
2836e4b17023SJohn Marino 	  else
2837e4b17023SJohn Marino 	    {
2838e4b17023SJohn Marino 	      gcc_assert (TREE_CODE (cfield) == RANGE_EXPR);
2839e4b17023SJohn Marino 	      index = tree_to_double_int (TREE_OPERAND (cfield, 0));
2840e4b17023SJohn Marino 	      max_index = tree_to_double_int (TREE_OPERAND (cfield, 1));
2841e4b17023SJohn Marino 	    }
2842e4b17023SJohn Marino 	}
2843e4b17023SJohn Marino       else
2844e4b17023SJohn Marino 	max_index = index = double_int_add (index, double_int_one);
2845e4b17023SJohn Marino 
2846e4b17023SJohn Marino       /* Do we have match?  */
2847e4b17023SJohn Marino       if (double_int_cmp (access_index, index, 1) >= 0
2848e4b17023SJohn Marino 	  && double_int_cmp (access_index, max_index, 1) <= 0)
2849e4b17023SJohn Marino 	return fold_ctor_reference (type, cval, inner_offset, size);
2850e4b17023SJohn Marino     }
2851e4b17023SJohn Marino   /* When memory is not explicitely mentioned in constructor,
2852e4b17023SJohn Marino      it is 0 (or out of range).  */
2853e4b17023SJohn Marino   return build_zero_cst (type);
2854e4b17023SJohn Marino }
2855e4b17023SJohn Marino 
2856e4b17023SJohn Marino /* CTOR is CONSTRUCTOR of an aggregate or vector.
2857e4b17023SJohn Marino    Fold reference of type TYPE and size SIZE to the memory at bit OFFSET.  */
2858e4b17023SJohn Marino 
2859e4b17023SJohn Marino static tree
fold_nonarray_ctor_reference(tree type,tree ctor,unsigned HOST_WIDE_INT offset,unsigned HOST_WIDE_INT size)2860e4b17023SJohn Marino fold_nonarray_ctor_reference (tree type, tree ctor,
2861e4b17023SJohn Marino 			      unsigned HOST_WIDE_INT offset,
2862e4b17023SJohn Marino 			      unsigned HOST_WIDE_INT size)
2863e4b17023SJohn Marino {
2864e4b17023SJohn Marino   unsigned HOST_WIDE_INT cnt;
2865e4b17023SJohn Marino   tree cfield, cval;
2866e4b17023SJohn Marino 
2867e4b17023SJohn Marino   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield,
2868e4b17023SJohn Marino 			    cval)
2869e4b17023SJohn Marino     {
2870e4b17023SJohn Marino       tree byte_offset = DECL_FIELD_OFFSET (cfield);
2871e4b17023SJohn Marino       tree field_offset = DECL_FIELD_BIT_OFFSET (cfield);
2872e4b17023SJohn Marino       tree field_size = DECL_SIZE (cfield);
2873e4b17023SJohn Marino       double_int bitoffset;
2874e4b17023SJohn Marino       double_int byte_offset_cst = tree_to_double_int (byte_offset);
2875e4b17023SJohn Marino       double_int bits_per_unit_cst = uhwi_to_double_int (BITS_PER_UNIT);
2876e4b17023SJohn Marino       double_int bitoffset_end, access_end;
2877e4b17023SJohn Marino 
2878e4b17023SJohn Marino       /* Variable sized objects in static constructors makes no sense,
2879e4b17023SJohn Marino 	 but field_size can be NULL for flexible array members.  */
2880e4b17023SJohn Marino       gcc_assert (TREE_CODE (field_offset) == INTEGER_CST
2881e4b17023SJohn Marino 		  && TREE_CODE (byte_offset) == INTEGER_CST
2882e4b17023SJohn Marino 		  && (field_size != NULL_TREE
2883e4b17023SJohn Marino 		      ? TREE_CODE (field_size) == INTEGER_CST
2884e4b17023SJohn Marino 		      : TREE_CODE (TREE_TYPE (cfield)) == ARRAY_TYPE));
2885e4b17023SJohn Marino 
2886e4b17023SJohn Marino       /* Compute bit offset of the field.  */
2887e4b17023SJohn Marino       bitoffset = double_int_add (tree_to_double_int (field_offset),
2888e4b17023SJohn Marino 				  double_int_mul (byte_offset_cst,
2889e4b17023SJohn Marino 						  bits_per_unit_cst));
2890e4b17023SJohn Marino       /* Compute bit offset where the field ends.  */
2891e4b17023SJohn Marino       if (field_size != NULL_TREE)
2892e4b17023SJohn Marino 	bitoffset_end = double_int_add (bitoffset,
2893e4b17023SJohn Marino 					tree_to_double_int (field_size));
2894e4b17023SJohn Marino       else
2895e4b17023SJohn Marino 	bitoffset_end = double_int_zero;
2896e4b17023SJohn Marino 
2897e4b17023SJohn Marino       access_end = double_int_add (uhwi_to_double_int (offset),
2898e4b17023SJohn Marino 				   uhwi_to_double_int (size));
2899e4b17023SJohn Marino 
2900e4b17023SJohn Marino       /* Is there any overlap between [OFFSET, OFFSET+SIZE) and
2901e4b17023SJohn Marino 	 [BITOFFSET, BITOFFSET_END)?  */
2902e4b17023SJohn Marino       if (double_int_cmp (access_end, bitoffset, 0) > 0
2903e4b17023SJohn Marino 	  && (field_size == NULL_TREE
2904e4b17023SJohn Marino 	      || double_int_cmp (uhwi_to_double_int (offset),
2905e4b17023SJohn Marino 				 bitoffset_end, 0) < 0))
2906e4b17023SJohn Marino 	{
2907e4b17023SJohn Marino 	  double_int inner_offset = double_int_sub (uhwi_to_double_int (offset),
2908e4b17023SJohn Marino 						    bitoffset);
2909e4b17023SJohn Marino 	  /* We do have overlap.  Now see if field is large enough to
2910e4b17023SJohn Marino 	     cover the access.  Give up for accesses spanning multiple
2911e4b17023SJohn Marino 	     fields.  */
2912e4b17023SJohn Marino 	  if (double_int_cmp (access_end, bitoffset_end, 0) > 0)
2913e4b17023SJohn Marino 	    return NULL_TREE;
2914e4b17023SJohn Marino 	  if (double_int_cmp (uhwi_to_double_int (offset), bitoffset, 0) < 0)
2915e4b17023SJohn Marino 	    return NULL_TREE;
2916e4b17023SJohn Marino 	  return fold_ctor_reference (type, cval,
2917e4b17023SJohn Marino 				      double_int_to_uhwi (inner_offset), size);
2918e4b17023SJohn Marino 	}
2919e4b17023SJohn Marino     }
2920e4b17023SJohn Marino   /* When memory is not explicitely mentioned in constructor, it is 0.  */
2921e4b17023SJohn Marino   return build_zero_cst (type);
2922e4b17023SJohn Marino }
2923e4b17023SJohn Marino 
2924e4b17023SJohn Marino /* CTOR is value initializing memory, fold reference of type TYPE and size SIZE
2925e4b17023SJohn Marino    to the memory at bit OFFSET.  */
2926e4b17023SJohn Marino 
2927e4b17023SJohn Marino static tree
fold_ctor_reference(tree type,tree ctor,unsigned HOST_WIDE_INT offset,unsigned HOST_WIDE_INT size)2928e4b17023SJohn Marino fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
2929e4b17023SJohn Marino 		     unsigned HOST_WIDE_INT size)
2930e4b17023SJohn Marino {
2931e4b17023SJohn Marino   tree ret;
2932e4b17023SJohn Marino 
2933e4b17023SJohn Marino   /* We found the field with exact match.  */
2934e4b17023SJohn Marino   if (useless_type_conversion_p (type, TREE_TYPE (ctor))
2935e4b17023SJohn Marino       && !offset)
2936e4b17023SJohn Marino     return canonicalize_constructor_val (ctor);
2937e4b17023SJohn Marino 
2938e4b17023SJohn Marino   /* We are at the end of walk, see if we can view convert the
2939e4b17023SJohn Marino      result.  */
2940e4b17023SJohn Marino   if (!AGGREGATE_TYPE_P (TREE_TYPE (ctor)) && !offset
2941e4b17023SJohn Marino       /* VIEW_CONVERT_EXPR is defined only for matching sizes.  */
2942e4b17023SJohn Marino       && operand_equal_p (TYPE_SIZE (type),
2943e4b17023SJohn Marino 			  TYPE_SIZE (TREE_TYPE (ctor)), 0))
2944e4b17023SJohn Marino     {
2945e4b17023SJohn Marino       ret = canonicalize_constructor_val (ctor);
2946e4b17023SJohn Marino       ret = fold_unary (VIEW_CONVERT_EXPR, type, ret);
2947e4b17023SJohn Marino       if (ret)
2948e4b17023SJohn Marino 	STRIP_NOPS (ret);
2949e4b17023SJohn Marino       return ret;
2950e4b17023SJohn Marino     }
2951e4b17023SJohn Marino   if (TREE_CODE (ctor) == STRING_CST)
2952e4b17023SJohn Marino     return fold_string_cst_ctor_reference (type, ctor, offset, size);
2953e4b17023SJohn Marino   if (TREE_CODE (ctor) == CONSTRUCTOR)
2954e4b17023SJohn Marino     {
2955e4b17023SJohn Marino 
2956e4b17023SJohn Marino       if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE
2957e4b17023SJohn Marino 	  || TREE_CODE (TREE_TYPE (ctor)) == VECTOR_TYPE)
2958e4b17023SJohn Marino 	return fold_array_ctor_reference (type, ctor, offset, size);
2959e4b17023SJohn Marino       else
2960e4b17023SJohn Marino 	return fold_nonarray_ctor_reference (type, ctor, offset, size);
2961e4b17023SJohn Marino     }
2962e4b17023SJohn Marino 
2963e4b17023SJohn Marino   return NULL_TREE;
2964e4b17023SJohn Marino }
2965e4b17023SJohn Marino 
2966e4b17023SJohn Marino /* Return the tree representing the element referenced by T if T is an
2967e4b17023SJohn Marino    ARRAY_REF or COMPONENT_REF into constant aggregates valuezing SSA
2968e4b17023SJohn Marino    names using VALUEIZE.  Return NULL_TREE otherwise.  */
2969e4b17023SJohn Marino 
2970e4b17023SJohn Marino tree
fold_const_aggregate_ref_1(tree t,tree (* valueize)(tree))2971e4b17023SJohn Marino fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
2972e4b17023SJohn Marino {
2973e4b17023SJohn Marino   tree ctor, idx, base;
2974e4b17023SJohn Marino   HOST_WIDE_INT offset, size, max_size;
2975e4b17023SJohn Marino   tree tem;
2976e4b17023SJohn Marino 
2977e4b17023SJohn Marino   if (TREE_THIS_VOLATILE (t))
2978e4b17023SJohn Marino     return NULL_TREE;
2979e4b17023SJohn Marino 
2980e4b17023SJohn Marino   if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
2981e4b17023SJohn Marino     return get_symbol_constant_value (t);
2982e4b17023SJohn Marino 
2983e4b17023SJohn Marino   tem = fold_read_from_constant_string (t);
2984e4b17023SJohn Marino   if (tem)
2985e4b17023SJohn Marino     return tem;
2986e4b17023SJohn Marino 
2987e4b17023SJohn Marino   switch (TREE_CODE (t))
2988e4b17023SJohn Marino     {
2989e4b17023SJohn Marino     case ARRAY_REF:
2990e4b17023SJohn Marino     case ARRAY_RANGE_REF:
2991e4b17023SJohn Marino       /* Constant indexes are handled well by get_base_constructor.
2992e4b17023SJohn Marino 	 Only special case variable offsets.
2993e4b17023SJohn Marino 	 FIXME: This code can't handle nested references with variable indexes
2994e4b17023SJohn Marino 	 (they will be handled only by iteration of ccp).  Perhaps we can bring
2995e4b17023SJohn Marino 	 get_ref_base_and_extent here and make it use a valueize callback.  */
2996e4b17023SJohn Marino       if (TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME
2997e4b17023SJohn Marino 	  && valueize
2998e4b17023SJohn Marino 	  && (idx = (*valueize) (TREE_OPERAND (t, 1)))
2999e4b17023SJohn Marino 	  && host_integerp (idx, 0))
3000e4b17023SJohn Marino 	{
3001e4b17023SJohn Marino 	  tree low_bound, unit_size;
3002e4b17023SJohn Marino 
3003e4b17023SJohn Marino 	  /* If the resulting bit-offset is constant, track it.  */
3004e4b17023SJohn Marino 	  if ((low_bound = array_ref_low_bound (t),
3005e4b17023SJohn Marino 	       host_integerp (low_bound, 0))
3006e4b17023SJohn Marino 	      && (unit_size = array_ref_element_size (t),
3007e4b17023SJohn Marino 		  host_integerp (unit_size, 1)))
3008e4b17023SJohn Marino 	    {
3009e4b17023SJohn Marino 	      offset = TREE_INT_CST_LOW (idx);
3010e4b17023SJohn Marino 	      offset -= TREE_INT_CST_LOW (low_bound);
3011e4b17023SJohn Marino 	      offset *= TREE_INT_CST_LOW (unit_size);
3012e4b17023SJohn Marino 	      offset *= BITS_PER_UNIT;
3013e4b17023SJohn Marino 
3014e4b17023SJohn Marino 	      base = TREE_OPERAND (t, 0);
3015e4b17023SJohn Marino 	      ctor = get_base_constructor (base, &offset, valueize);
3016e4b17023SJohn Marino 	      /* Empty constructor.  Always fold to 0.  */
3017e4b17023SJohn Marino 	      if (ctor == error_mark_node)
3018e4b17023SJohn Marino 		return build_zero_cst (TREE_TYPE (t));
3019e4b17023SJohn Marino 	      /* Out of bound array access.  Value is undefined,
3020e4b17023SJohn Marino 		 but don't fold.  */
3021e4b17023SJohn Marino 	      if (offset < 0)
3022e4b17023SJohn Marino 		return NULL_TREE;
3023e4b17023SJohn Marino 	      /* We can not determine ctor.  */
3024e4b17023SJohn Marino 	      if (!ctor)
3025e4b17023SJohn Marino 		return NULL_TREE;
3026e4b17023SJohn Marino 	      return fold_ctor_reference (TREE_TYPE (t), ctor, offset,
3027e4b17023SJohn Marino 					  TREE_INT_CST_LOW (unit_size)
3028e4b17023SJohn Marino 					  * BITS_PER_UNIT);
3029e4b17023SJohn Marino 	    }
3030e4b17023SJohn Marino 	}
3031e4b17023SJohn Marino       /* Fallthru.  */
3032e4b17023SJohn Marino 
3033e4b17023SJohn Marino     case COMPONENT_REF:
3034e4b17023SJohn Marino     case BIT_FIELD_REF:
3035e4b17023SJohn Marino     case TARGET_MEM_REF:
3036e4b17023SJohn Marino     case MEM_REF:
3037e4b17023SJohn Marino       base = get_ref_base_and_extent (t, &offset, &size, &max_size);
3038e4b17023SJohn Marino       ctor = get_base_constructor (base, &offset, valueize);
3039e4b17023SJohn Marino 
3040e4b17023SJohn Marino       /* Empty constructor.  Always fold to 0.  */
3041e4b17023SJohn Marino       if (ctor == error_mark_node)
3042e4b17023SJohn Marino 	return build_zero_cst (TREE_TYPE (t));
3043e4b17023SJohn Marino       /* We do not know precise address.  */
3044e4b17023SJohn Marino       if (max_size == -1 || max_size != size)
3045e4b17023SJohn Marino 	return NULL_TREE;
3046e4b17023SJohn Marino       /* We can not determine ctor.  */
3047e4b17023SJohn Marino       if (!ctor)
3048e4b17023SJohn Marino 	return NULL_TREE;
3049e4b17023SJohn Marino 
3050e4b17023SJohn Marino       /* Out of bound array access.  Value is undefined, but don't fold.  */
3051e4b17023SJohn Marino       if (offset < 0)
3052e4b17023SJohn Marino 	return NULL_TREE;
3053e4b17023SJohn Marino 
3054e4b17023SJohn Marino       return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size);
3055e4b17023SJohn Marino 
3056e4b17023SJohn Marino     case REALPART_EXPR:
3057e4b17023SJohn Marino     case IMAGPART_EXPR:
3058e4b17023SJohn Marino       {
3059e4b17023SJohn Marino 	tree c = fold_const_aggregate_ref_1 (TREE_OPERAND (t, 0), valueize);
3060e4b17023SJohn Marino 	if (c && TREE_CODE (c) == COMPLEX_CST)
3061e4b17023SJohn Marino 	  return fold_build1_loc (EXPR_LOCATION (t),
3062e4b17023SJohn Marino 			      TREE_CODE (t), TREE_TYPE (t), c);
3063e4b17023SJohn Marino 	break;
3064e4b17023SJohn Marino       }
3065e4b17023SJohn Marino 
3066e4b17023SJohn Marino     default:
3067e4b17023SJohn Marino       break;
3068e4b17023SJohn Marino     }
3069e4b17023SJohn Marino 
3070e4b17023SJohn Marino   return NULL_TREE;
3071e4b17023SJohn Marino }
3072e4b17023SJohn Marino 
3073e4b17023SJohn Marino tree
fold_const_aggregate_ref(tree t)3074e4b17023SJohn Marino fold_const_aggregate_ref (tree t)
3075e4b17023SJohn Marino {
3076e4b17023SJohn Marino   return fold_const_aggregate_ref_1 (t, NULL);
3077e4b17023SJohn Marino }
3078e4b17023SJohn Marino 
3079e4b17023SJohn Marino /* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
3080e4b17023SJohn Marino    is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
3081e4b17023SJohn Marino    KNOWN_BINFO carries the binfo describing the true type of
3082e4b17023SJohn Marino    OBJ_TYPE_REF_OBJECT(REF).  */
3083e4b17023SJohn Marino 
3084e4b17023SJohn Marino tree
gimple_get_virt_method_for_binfo(HOST_WIDE_INT token,tree known_binfo)3085e4b17023SJohn Marino gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
3086e4b17023SJohn Marino {
3087e4b17023SJohn Marino   unsigned HOST_WIDE_INT offset, size;
3088e4b17023SJohn Marino   tree v, fn;
3089e4b17023SJohn Marino 
3090e4b17023SJohn Marino   v = BINFO_VTABLE (known_binfo);
3091e4b17023SJohn Marino   /* If there is no virtual methods table, leave the OBJ_TYPE_REF alone.  */
3092e4b17023SJohn Marino   if (!v)
3093e4b17023SJohn Marino     return NULL_TREE;
3094e4b17023SJohn Marino 
3095e4b17023SJohn Marino   if (TREE_CODE (v) == POINTER_PLUS_EXPR)
3096e4b17023SJohn Marino     {
3097e4b17023SJohn Marino       offset = tree_low_cst (TREE_OPERAND (v, 1), 1) * BITS_PER_UNIT;
3098e4b17023SJohn Marino       v = TREE_OPERAND (v, 0);
3099e4b17023SJohn Marino     }
3100e4b17023SJohn Marino   else
3101e4b17023SJohn Marino     offset = 0;
3102e4b17023SJohn Marino 
3103e4b17023SJohn Marino   if (TREE_CODE (v) != ADDR_EXPR)
3104e4b17023SJohn Marino     return NULL_TREE;
3105e4b17023SJohn Marino   v = TREE_OPERAND (v, 0);
3106e4b17023SJohn Marino 
3107e4b17023SJohn Marino   if (TREE_CODE (v) != VAR_DECL
3108e4b17023SJohn Marino       || !DECL_VIRTUAL_P (v)
3109e4b17023SJohn Marino       || !DECL_INITIAL (v)
3110e4b17023SJohn Marino       || DECL_INITIAL (v) == error_mark_node)
3111e4b17023SJohn Marino     return NULL_TREE;
3112e4b17023SJohn Marino   gcc_checking_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
3113e4b17023SJohn Marino   size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))), 1);
3114e4b17023SJohn Marino   offset += token * size;
3115e4b17023SJohn Marino   fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), DECL_INITIAL (v),
3116e4b17023SJohn Marino 			    offset, size);
3117e4b17023SJohn Marino   if (!fn || integer_zerop (fn))
3118e4b17023SJohn Marino     return NULL_TREE;
3119e4b17023SJohn Marino   gcc_assert (TREE_CODE (fn) == ADDR_EXPR
3120e4b17023SJohn Marino 	      || TREE_CODE (fn) == FDESC_EXPR);
3121e4b17023SJohn Marino   fn = TREE_OPERAND (fn, 0);
3122e4b17023SJohn Marino   gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
3123e4b17023SJohn Marino 
3124e4b17023SJohn Marino   /* When cgraph node is missing and function is not public, we cannot
3125e4b17023SJohn Marino      devirtualize.  This can happen in WHOPR when the actual method
3126e4b17023SJohn Marino      ends up in other partition, because we found devirtualization
3127e4b17023SJohn Marino      possibility too late.  */
3128e4b17023SJohn Marino   if (!can_refer_decl_in_current_unit_p (fn))
3129e4b17023SJohn Marino     return NULL_TREE;
3130e4b17023SJohn Marino 
3131e4b17023SJohn Marino   return fn;
3132e4b17023SJohn Marino }
3133e4b17023SJohn Marino 
3134e4b17023SJohn Marino /* Return true iff VAL is a gimple expression that is known to be
3135e4b17023SJohn Marino    non-negative.  Restricted to floating-point inputs.  */
3136e4b17023SJohn Marino 
3137e4b17023SJohn Marino bool
gimple_val_nonnegative_real_p(tree val)3138e4b17023SJohn Marino gimple_val_nonnegative_real_p (tree val)
3139e4b17023SJohn Marino {
3140e4b17023SJohn Marino   gimple def_stmt;
3141e4b17023SJohn Marino 
3142e4b17023SJohn Marino   gcc_assert (val && SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)));
3143e4b17023SJohn Marino 
3144e4b17023SJohn Marino   /* Use existing logic for non-gimple trees.  */
3145e4b17023SJohn Marino   if (tree_expr_nonnegative_p (val))
3146e4b17023SJohn Marino     return true;
3147e4b17023SJohn Marino 
3148e4b17023SJohn Marino   if (TREE_CODE (val) != SSA_NAME)
3149e4b17023SJohn Marino     return false;
3150e4b17023SJohn Marino 
3151e4b17023SJohn Marino   /* Currently we look only at the immediately defining statement
3152e4b17023SJohn Marino      to make this determination, since recursion on defining
3153e4b17023SJohn Marino      statements of operands can lead to quadratic behavior in the
3154e4b17023SJohn Marino      worst case.  This is expected to catch almost all occurrences
3155e4b17023SJohn Marino      in practice.  It would be possible to implement limited-depth
3156e4b17023SJohn Marino      recursion if important cases are lost.  Alternatively, passes
3157e4b17023SJohn Marino      that need this information (such as the pow/powi lowering code
3158e4b17023SJohn Marino      in the cse_sincos pass) could be revised to provide it through
3159e4b17023SJohn Marino      dataflow propagation.  */
3160e4b17023SJohn Marino 
3161e4b17023SJohn Marino   def_stmt = SSA_NAME_DEF_STMT (val);
3162e4b17023SJohn Marino 
3163e4b17023SJohn Marino   if (is_gimple_assign (def_stmt))
3164e4b17023SJohn Marino     {
3165e4b17023SJohn Marino       tree op0, op1;
3166e4b17023SJohn Marino 
3167e4b17023SJohn Marino       /* See fold-const.c:tree_expr_nonnegative_p for additional
3168e4b17023SJohn Marino 	 cases that could be handled with recursion.  */
3169e4b17023SJohn Marino 
3170e4b17023SJohn Marino       switch (gimple_assign_rhs_code (def_stmt))
3171e4b17023SJohn Marino 	{
3172e4b17023SJohn Marino 	case ABS_EXPR:
3173e4b17023SJohn Marino 	  /* Always true for floating-point operands.  */
3174e4b17023SJohn Marino 	  return true;
3175e4b17023SJohn Marino 
3176e4b17023SJohn Marino 	case MULT_EXPR:
3177e4b17023SJohn Marino 	  /* True if the two operands are identical (since we are
3178e4b17023SJohn Marino 	     restricted to floating-point inputs).  */
3179e4b17023SJohn Marino 	  op0 = gimple_assign_rhs1 (def_stmt);
3180e4b17023SJohn Marino 	  op1 = gimple_assign_rhs2 (def_stmt);
3181e4b17023SJohn Marino 
3182e4b17023SJohn Marino 	  if (op0 == op1
3183e4b17023SJohn Marino 	      || operand_equal_p (op0, op1, 0))
3184e4b17023SJohn Marino 	    return true;
3185e4b17023SJohn Marino 
3186e4b17023SJohn Marino 	default:
3187e4b17023SJohn Marino 	  return false;
3188e4b17023SJohn Marino 	}
3189e4b17023SJohn Marino     }
3190e4b17023SJohn Marino   else if (is_gimple_call (def_stmt))
3191e4b17023SJohn Marino     {
3192e4b17023SJohn Marino       tree fndecl = gimple_call_fndecl (def_stmt);
3193e4b17023SJohn Marino       if (fndecl
3194e4b17023SJohn Marino 	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
3195e4b17023SJohn Marino 	{
3196e4b17023SJohn Marino 	  tree arg1;
3197e4b17023SJohn Marino 
3198e4b17023SJohn Marino 	  switch (DECL_FUNCTION_CODE (fndecl))
3199e4b17023SJohn Marino 	    {
3200e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_ACOS):
3201e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_ACOSH):
3202e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_CABS):
3203e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_COSH):
3204e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_ERFC):
3205e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_EXP):
3206e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_EXP10):
3207e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_EXP2):
3208e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_FABS):
3209e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_FDIM):
3210e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_HYPOT):
3211e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_POW10):
3212e4b17023SJohn Marino 	      return true;
3213e4b17023SJohn Marino 
3214e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_SQRT):
3215e4b17023SJohn Marino 	      /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
3216e4b17023SJohn Marino 		 nonnegative inputs.  */
3217e4b17023SJohn Marino 	      if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (val))))
3218e4b17023SJohn Marino 		return true;
3219e4b17023SJohn Marino 
3220e4b17023SJohn Marino 	      break;
3221e4b17023SJohn Marino 
3222e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_POWI):
3223e4b17023SJohn Marino 	      /* True if the second argument is an even integer.  */
3224e4b17023SJohn Marino 	      arg1 = gimple_call_arg (def_stmt, 1);
3225e4b17023SJohn Marino 
3226e4b17023SJohn Marino 	      if (TREE_CODE (arg1) == INTEGER_CST
3227e4b17023SJohn Marino 		  && (TREE_INT_CST_LOW (arg1) & 1) == 0)
3228e4b17023SJohn Marino 		return true;
3229e4b17023SJohn Marino 
3230e4b17023SJohn Marino 	      break;
3231e4b17023SJohn Marino 
3232e4b17023SJohn Marino 	    CASE_FLT_FN (BUILT_IN_POW):
3233e4b17023SJohn Marino 	      /* True if the second argument is an even integer-valued
3234e4b17023SJohn Marino 		 real.  */
3235e4b17023SJohn Marino 	      arg1 = gimple_call_arg (def_stmt, 1);
3236e4b17023SJohn Marino 
3237e4b17023SJohn Marino 	      if (TREE_CODE (arg1) == REAL_CST)
3238e4b17023SJohn Marino 		{
3239e4b17023SJohn Marino 		  REAL_VALUE_TYPE c;
3240e4b17023SJohn Marino 		  HOST_WIDE_INT n;
3241e4b17023SJohn Marino 
3242e4b17023SJohn Marino 		  c = TREE_REAL_CST (arg1);
3243e4b17023SJohn Marino 		  n = real_to_integer (&c);
3244e4b17023SJohn Marino 
3245e4b17023SJohn Marino 		  if ((n & 1) == 0)
3246e4b17023SJohn Marino 		    {
3247e4b17023SJohn Marino 		      REAL_VALUE_TYPE cint;
3248e4b17023SJohn Marino 		      real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
3249e4b17023SJohn Marino 		      if (real_identical (&c, &cint))
3250e4b17023SJohn Marino 			return true;
3251e4b17023SJohn Marino 		    }
3252e4b17023SJohn Marino 		}
3253e4b17023SJohn Marino 
3254e4b17023SJohn Marino 	      break;
3255e4b17023SJohn Marino 
3256e4b17023SJohn Marino 	    default:
3257e4b17023SJohn Marino 	      return false;
3258e4b17023SJohn Marino 	    }
3259e4b17023SJohn Marino 	}
3260e4b17023SJohn Marino     }
3261e4b17023SJohn Marino 
3262e4b17023SJohn Marino   return false;
3263e4b17023SJohn Marino }
3264