11debfc3dSmrg /* __builtin_object_size (ptr, object_size_type) computation
2*8feb0f0bSmrg Copyright (C) 2004-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Jakub Jelinek <jakub@redhat.com>
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful,
131debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
141debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
151debfc3dSmrg GNU General Public License for more details.
161debfc3dSmrg
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3. If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>. */
201debfc3dSmrg
211debfc3dSmrg #include "config.h"
221debfc3dSmrg #include "system.h"
231debfc3dSmrg #include "coretypes.h"
241debfc3dSmrg #include "backend.h"
251debfc3dSmrg #include "tree.h"
261debfc3dSmrg #include "gimple.h"
271debfc3dSmrg #include "tree-pass.h"
281debfc3dSmrg #include "ssa.h"
291debfc3dSmrg #include "gimple-pretty-print.h"
301debfc3dSmrg #include "fold-const.h"
311debfc3dSmrg #include "tree-object-size.h"
321debfc3dSmrg #include "gimple-fold.h"
331debfc3dSmrg #include "gimple-iterator.h"
341debfc3dSmrg #include "tree-cfg.h"
35a2dc1f3fSmrg #include "stringpool.h"
36a2dc1f3fSmrg #include "attribs.h"
371debfc3dSmrg
381debfc3dSmrg struct object_size_info
391debfc3dSmrg {
401debfc3dSmrg int object_size_type;
411debfc3dSmrg unsigned char pass;
421debfc3dSmrg bool changed;
431debfc3dSmrg bitmap visited, reexamine;
441debfc3dSmrg unsigned int *depths;
451debfc3dSmrg unsigned int *stack, *tos;
461debfc3dSmrg };
471debfc3dSmrg
481debfc3dSmrg static const unsigned HOST_WIDE_INT unknown[4] = {
491debfc3dSmrg HOST_WIDE_INT_M1U,
501debfc3dSmrg HOST_WIDE_INT_M1U,
511debfc3dSmrg 0,
521debfc3dSmrg 0
531debfc3dSmrg };
541debfc3dSmrg
551debfc3dSmrg static tree compute_object_offset (const_tree, const_tree);
561debfc3dSmrg static bool addr_object_size (struct object_size_info *,
57*8feb0f0bSmrg const_tree, int, unsigned HOST_WIDE_INT *,
58*8feb0f0bSmrg tree * = NULL, tree * = NULL);
591debfc3dSmrg static unsigned HOST_WIDE_INT alloc_object_size (const gcall *, int);
601debfc3dSmrg static tree pass_through_call (const gcall *);
611debfc3dSmrg static void collect_object_sizes_for (struct object_size_info *, tree);
621debfc3dSmrg static void expr_object_size (struct object_size_info *, tree, tree);
631debfc3dSmrg static bool merge_object_sizes (struct object_size_info *, tree, tree,
641debfc3dSmrg unsigned HOST_WIDE_INT);
651debfc3dSmrg static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *);
661debfc3dSmrg static bool cond_expr_object_size (struct object_size_info *, tree, gimple *);
671debfc3dSmrg static void init_offset_limit (void);
681debfc3dSmrg static void check_for_plus_in_loops (struct object_size_info *, tree);
691debfc3dSmrg static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
701debfc3dSmrg unsigned int);
711debfc3dSmrg
721debfc3dSmrg /* object_sizes[0] is upper bound for number of bytes till the end of
731debfc3dSmrg the object.
741debfc3dSmrg object_sizes[1] is upper bound for number of bytes till the end of
751debfc3dSmrg the subobject (innermost array or field with address taken).
761debfc3dSmrg object_sizes[2] is lower bound for number of bytes till the end of
771debfc3dSmrg the object and object_sizes[3] lower bound for subobject. */
781debfc3dSmrg static vec<unsigned HOST_WIDE_INT> object_sizes[4];
791debfc3dSmrg
801debfc3dSmrg /* Bitmaps what object sizes have been computed already. */
811debfc3dSmrg static bitmap computed[4];
821debfc3dSmrg
831debfc3dSmrg /* Maximum value of offset we consider to be addition. */
841debfc3dSmrg static unsigned HOST_WIDE_INT offset_limit;
851debfc3dSmrg
861debfc3dSmrg
871debfc3dSmrg /* Initialize OFFSET_LIMIT variable. */
881debfc3dSmrg static void
init_offset_limit(void)891debfc3dSmrg init_offset_limit (void)
901debfc3dSmrg {
911debfc3dSmrg if (tree_fits_uhwi_p (TYPE_MAX_VALUE (sizetype)))
921debfc3dSmrg offset_limit = tree_to_uhwi (TYPE_MAX_VALUE (sizetype));
931debfc3dSmrg else
941debfc3dSmrg offset_limit = -1;
951debfc3dSmrg offset_limit /= 2;
961debfc3dSmrg }
971debfc3dSmrg
981debfc3dSmrg
991debfc3dSmrg /* Compute offset of EXPR within VAR. Return error_mark_node
1001debfc3dSmrg if unknown. */
1011debfc3dSmrg
1021debfc3dSmrg static tree
compute_object_offset(const_tree expr,const_tree var)1031debfc3dSmrg compute_object_offset (const_tree expr, const_tree var)
1041debfc3dSmrg {
1051debfc3dSmrg enum tree_code code = PLUS_EXPR;
1061debfc3dSmrg tree base, off, t;
1071debfc3dSmrg
1081debfc3dSmrg if (expr == var)
1091debfc3dSmrg return size_zero_node;
1101debfc3dSmrg
1111debfc3dSmrg switch (TREE_CODE (expr))
1121debfc3dSmrg {
1131debfc3dSmrg case COMPONENT_REF:
1141debfc3dSmrg base = compute_object_offset (TREE_OPERAND (expr, 0), var);
1151debfc3dSmrg if (base == error_mark_node)
1161debfc3dSmrg return base;
1171debfc3dSmrg
1181debfc3dSmrg t = TREE_OPERAND (expr, 1);
1191debfc3dSmrg off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
1201debfc3dSmrg size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
1211debfc3dSmrg / BITS_PER_UNIT));
1221debfc3dSmrg break;
1231debfc3dSmrg
1241debfc3dSmrg case REALPART_EXPR:
1251debfc3dSmrg CASE_CONVERT:
1261debfc3dSmrg case VIEW_CONVERT_EXPR:
1271debfc3dSmrg case NON_LVALUE_EXPR:
1281debfc3dSmrg return compute_object_offset (TREE_OPERAND (expr, 0), var);
1291debfc3dSmrg
1301debfc3dSmrg case IMAGPART_EXPR:
1311debfc3dSmrg base = compute_object_offset (TREE_OPERAND (expr, 0), var);
1321debfc3dSmrg if (base == error_mark_node)
1331debfc3dSmrg return base;
1341debfc3dSmrg
1351debfc3dSmrg off = TYPE_SIZE_UNIT (TREE_TYPE (expr));
1361debfc3dSmrg break;
1371debfc3dSmrg
1381debfc3dSmrg case ARRAY_REF:
1391debfc3dSmrg base = compute_object_offset (TREE_OPERAND (expr, 0), var);
1401debfc3dSmrg if (base == error_mark_node)
1411debfc3dSmrg return base;
1421debfc3dSmrg
1431debfc3dSmrg t = TREE_OPERAND (expr, 1);
1441debfc3dSmrg tree low_bound, unit_size;
1451debfc3dSmrg low_bound = array_ref_low_bound (CONST_CAST_TREE (expr));
1461debfc3dSmrg unit_size = array_ref_element_size (CONST_CAST_TREE (expr));
1471debfc3dSmrg if (! integer_zerop (low_bound))
1481debfc3dSmrg t = fold_build2 (MINUS_EXPR, TREE_TYPE (t), t, low_bound);
1491debfc3dSmrg if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
1501debfc3dSmrg {
1511debfc3dSmrg code = MINUS_EXPR;
1521debfc3dSmrg t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
1531debfc3dSmrg }
1541debfc3dSmrg t = fold_convert (sizetype, t);
1551debfc3dSmrg off = size_binop (MULT_EXPR, unit_size, t);
1561debfc3dSmrg break;
1571debfc3dSmrg
1581debfc3dSmrg case MEM_REF:
1591debfc3dSmrg gcc_assert (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR);
1601debfc3dSmrg return wide_int_to_tree (sizetype, mem_ref_offset (expr));
1611debfc3dSmrg
1621debfc3dSmrg default:
1631debfc3dSmrg return error_mark_node;
1641debfc3dSmrg }
1651debfc3dSmrg
1661debfc3dSmrg return size_binop (code, base, off);
1671debfc3dSmrg }
1681debfc3dSmrg
1691debfc3dSmrg
1701debfc3dSmrg /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
1711debfc3dSmrg OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
1721debfc3dSmrg If unknown, return unknown[object_size_type]. */
1731debfc3dSmrg
1741debfc3dSmrg static bool
addr_object_size(struct object_size_info * osi,const_tree ptr,int object_size_type,unsigned HOST_WIDE_INT * psize,tree * pdecl,tree * poff)1751debfc3dSmrg addr_object_size (struct object_size_info *osi, const_tree ptr,
176*8feb0f0bSmrg int object_size_type, unsigned HOST_WIDE_INT *psize,
177*8feb0f0bSmrg tree *pdecl /* = NULL */, tree *poff /* = NULL */)
1781debfc3dSmrg {
1791debfc3dSmrg tree pt_var, pt_var_size = NULL_TREE, var_size, bytes;
1801debfc3dSmrg
181*8feb0f0bSmrg tree dummy_decl, dummy_off = size_zero_node;
182*8feb0f0bSmrg if (!pdecl)
183*8feb0f0bSmrg pdecl = &dummy_decl;
184*8feb0f0bSmrg if (!poff)
185*8feb0f0bSmrg poff = &dummy_off;
186*8feb0f0bSmrg
1871debfc3dSmrg gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
1881debfc3dSmrg
1891debfc3dSmrg /* Set to unknown and overwrite just before returning if the size
1901debfc3dSmrg could be determined. */
1911debfc3dSmrg *psize = unknown[object_size_type];
1921debfc3dSmrg
1931debfc3dSmrg pt_var = TREE_OPERAND (ptr, 0);
1941debfc3dSmrg while (handled_component_p (pt_var))
1951debfc3dSmrg pt_var = TREE_OPERAND (pt_var, 0);
1961debfc3dSmrg
1971debfc3dSmrg if (pt_var
1981debfc3dSmrg && TREE_CODE (pt_var) == MEM_REF)
1991debfc3dSmrg {
2001debfc3dSmrg unsigned HOST_WIDE_INT sz;
2011debfc3dSmrg
2021debfc3dSmrg if (!osi || (object_size_type & 1) != 0
2031debfc3dSmrg || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME)
2041debfc3dSmrg {
2051debfc3dSmrg compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
206*8feb0f0bSmrg object_size_type & ~1, &sz, pdecl, poff);
2071debfc3dSmrg }
2081debfc3dSmrg else
2091debfc3dSmrg {
2101debfc3dSmrg tree var = TREE_OPERAND (pt_var, 0);
2111debfc3dSmrg if (osi->pass == 0)
2121debfc3dSmrg collect_object_sizes_for (osi, var);
2131debfc3dSmrg if (bitmap_bit_p (computed[object_size_type],
2141debfc3dSmrg SSA_NAME_VERSION (var)))
2151debfc3dSmrg sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)];
2161debfc3dSmrg else
2171debfc3dSmrg sz = unknown[object_size_type];
2181debfc3dSmrg }
2191debfc3dSmrg if (sz != unknown[object_size_type])
2201debfc3dSmrg {
221a2dc1f3fSmrg offset_int mem_offset;
222a2dc1f3fSmrg if (mem_ref_offset (pt_var).is_constant (&mem_offset))
223a2dc1f3fSmrg {
224a2dc1f3fSmrg offset_int dsz = wi::sub (sz, mem_offset);
2251debfc3dSmrg if (wi::neg_p (dsz))
2261debfc3dSmrg sz = 0;
2271debfc3dSmrg else if (wi::fits_uhwi_p (dsz))
2281debfc3dSmrg sz = dsz.to_uhwi ();
2291debfc3dSmrg else
2301debfc3dSmrg sz = unknown[object_size_type];
2311debfc3dSmrg }
232a2dc1f3fSmrg else
233a2dc1f3fSmrg sz = unknown[object_size_type];
234a2dc1f3fSmrg }
2351debfc3dSmrg
2361debfc3dSmrg if (sz != unknown[object_size_type] && sz < offset_limit)
2371debfc3dSmrg pt_var_size = size_int (sz);
2381debfc3dSmrg }
2391debfc3dSmrg else if (pt_var
2401debfc3dSmrg && DECL_P (pt_var)
2411debfc3dSmrg && tree_fits_uhwi_p (DECL_SIZE_UNIT (pt_var))
2421debfc3dSmrg && tree_to_uhwi (DECL_SIZE_UNIT (pt_var)) < offset_limit)
243*8feb0f0bSmrg {
244*8feb0f0bSmrg *pdecl = pt_var;
2451debfc3dSmrg pt_var_size = DECL_SIZE_UNIT (pt_var);
246*8feb0f0bSmrg }
2471debfc3dSmrg else if (pt_var
2481debfc3dSmrg && TREE_CODE (pt_var) == STRING_CST
2491debfc3dSmrg && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
2501debfc3dSmrg && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
2511debfc3dSmrg && tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
2521debfc3dSmrg < offset_limit)
2531debfc3dSmrg pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
2541debfc3dSmrg else
2551debfc3dSmrg return false;
2561debfc3dSmrg
2571debfc3dSmrg if (pt_var != TREE_OPERAND (ptr, 0))
2581debfc3dSmrg {
2591debfc3dSmrg tree var;
2601debfc3dSmrg
2611debfc3dSmrg if (object_size_type & 1)
2621debfc3dSmrg {
2631debfc3dSmrg var = TREE_OPERAND (ptr, 0);
2641debfc3dSmrg
2651debfc3dSmrg while (var != pt_var
2661debfc3dSmrg && TREE_CODE (var) != BIT_FIELD_REF
2671debfc3dSmrg && TREE_CODE (var) != COMPONENT_REF
2681debfc3dSmrg && TREE_CODE (var) != ARRAY_REF
2691debfc3dSmrg && TREE_CODE (var) != ARRAY_RANGE_REF
2701debfc3dSmrg && TREE_CODE (var) != REALPART_EXPR
2711debfc3dSmrg && TREE_CODE (var) != IMAGPART_EXPR)
2721debfc3dSmrg var = TREE_OPERAND (var, 0);
2731debfc3dSmrg if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
2741debfc3dSmrg var = TREE_OPERAND (var, 0);
2751debfc3dSmrg if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
2761debfc3dSmrg || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
2771debfc3dSmrg || (pt_var_size
2781debfc3dSmrg && tree_int_cst_lt (pt_var_size,
2791debfc3dSmrg TYPE_SIZE_UNIT (TREE_TYPE (var)))))
2801debfc3dSmrg var = pt_var;
2811debfc3dSmrg else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
2821debfc3dSmrg {
2831debfc3dSmrg tree v = var;
2841debfc3dSmrg /* For &X->fld, compute object size only if fld isn't the last
2851debfc3dSmrg field, as struct { int i; char c[1]; } is often used instead
2861debfc3dSmrg of flexible array member. */
2871debfc3dSmrg while (v && v != pt_var)
2881debfc3dSmrg switch (TREE_CODE (v))
2891debfc3dSmrg {
2901debfc3dSmrg case ARRAY_REF:
2911debfc3dSmrg if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
2921debfc3dSmrg && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
2931debfc3dSmrg {
2941debfc3dSmrg tree domain
2951debfc3dSmrg = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
2961debfc3dSmrg if (domain
2971debfc3dSmrg && TYPE_MAX_VALUE (domain)
2981debfc3dSmrg && TREE_CODE (TYPE_MAX_VALUE (domain))
2991debfc3dSmrg == INTEGER_CST
3001debfc3dSmrg && tree_int_cst_lt (TREE_OPERAND (v, 1),
3011debfc3dSmrg TYPE_MAX_VALUE (domain)))
3021debfc3dSmrg {
3031debfc3dSmrg v = NULL_TREE;
3041debfc3dSmrg break;
3051debfc3dSmrg }
3061debfc3dSmrg }
3071debfc3dSmrg v = TREE_OPERAND (v, 0);
3081debfc3dSmrg break;
3091debfc3dSmrg case REALPART_EXPR:
3101debfc3dSmrg case IMAGPART_EXPR:
3111debfc3dSmrg v = NULL_TREE;
3121debfc3dSmrg break;
3131debfc3dSmrg case COMPONENT_REF:
3141debfc3dSmrg if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
3151debfc3dSmrg {
3161debfc3dSmrg v = NULL_TREE;
3171debfc3dSmrg break;
3181debfc3dSmrg }
3191debfc3dSmrg while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
3201debfc3dSmrg if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3211debfc3dSmrg != UNION_TYPE
3221debfc3dSmrg && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3231debfc3dSmrg != QUAL_UNION_TYPE)
3241debfc3dSmrg break;
3251debfc3dSmrg else
3261debfc3dSmrg v = TREE_OPERAND (v, 0);
3271debfc3dSmrg if (TREE_CODE (v) == COMPONENT_REF
3281debfc3dSmrg && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3291debfc3dSmrg == RECORD_TYPE)
3301debfc3dSmrg {
3311debfc3dSmrg tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
3321debfc3dSmrg for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
3331debfc3dSmrg if (TREE_CODE (fld_chain) == FIELD_DECL)
3341debfc3dSmrg break;
3351debfc3dSmrg
3361debfc3dSmrg if (fld_chain)
3371debfc3dSmrg {
3381debfc3dSmrg v = NULL_TREE;
3391debfc3dSmrg break;
3401debfc3dSmrg }
3411debfc3dSmrg v = TREE_OPERAND (v, 0);
3421debfc3dSmrg }
3431debfc3dSmrg while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
3441debfc3dSmrg if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3451debfc3dSmrg != UNION_TYPE
3461debfc3dSmrg && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3471debfc3dSmrg != QUAL_UNION_TYPE)
3481debfc3dSmrg break;
3491debfc3dSmrg else
3501debfc3dSmrg v = TREE_OPERAND (v, 0);
3511debfc3dSmrg if (v != pt_var)
3521debfc3dSmrg v = NULL_TREE;
3531debfc3dSmrg else
3541debfc3dSmrg v = pt_var;
3551debfc3dSmrg break;
3561debfc3dSmrg default:
3571debfc3dSmrg v = pt_var;
3581debfc3dSmrg break;
3591debfc3dSmrg }
3601debfc3dSmrg if (v == pt_var)
3611debfc3dSmrg var = pt_var;
3621debfc3dSmrg }
3631debfc3dSmrg }
3641debfc3dSmrg else
3651debfc3dSmrg var = pt_var;
3661debfc3dSmrg
3671debfc3dSmrg if (var != pt_var)
3681debfc3dSmrg var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
3691debfc3dSmrg else if (!pt_var_size)
3701debfc3dSmrg return false;
3711debfc3dSmrg else
3721debfc3dSmrg var_size = pt_var_size;
3731debfc3dSmrg bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
3741debfc3dSmrg if (bytes != error_mark_node)
3751debfc3dSmrg {
3761debfc3dSmrg if (TREE_CODE (bytes) == INTEGER_CST
3771debfc3dSmrg && tree_int_cst_lt (var_size, bytes))
3781debfc3dSmrg bytes = size_zero_node;
3791debfc3dSmrg else
3801debfc3dSmrg bytes = size_binop (MINUS_EXPR, var_size, bytes);
381*8feb0f0bSmrg *poff = bytes;
3821debfc3dSmrg }
3831debfc3dSmrg if (var != pt_var
3841debfc3dSmrg && pt_var_size
3851debfc3dSmrg && TREE_CODE (pt_var) == MEM_REF
3861debfc3dSmrg && bytes != error_mark_node)
3871debfc3dSmrg {
3881debfc3dSmrg tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
3891debfc3dSmrg if (bytes2 != error_mark_node)
3901debfc3dSmrg {
3911debfc3dSmrg if (TREE_CODE (bytes2) == INTEGER_CST
3921debfc3dSmrg && tree_int_cst_lt (pt_var_size, bytes2))
3931debfc3dSmrg bytes2 = size_zero_node;
3941debfc3dSmrg else
3951debfc3dSmrg bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2);
396*8feb0f0bSmrg *poff = size_binop (PLUS_EXPR, *poff, bytes2);
3971debfc3dSmrg bytes = size_binop (MIN_EXPR, bytes, bytes2);
3981debfc3dSmrg }
3991debfc3dSmrg }
4001debfc3dSmrg }
4011debfc3dSmrg else if (!pt_var_size)
4021debfc3dSmrg return false;
4031debfc3dSmrg else
4041debfc3dSmrg bytes = pt_var_size;
4051debfc3dSmrg
4061debfc3dSmrg if (tree_fits_uhwi_p (bytes))
4071debfc3dSmrg {
4081debfc3dSmrg *psize = tree_to_uhwi (bytes);
4091debfc3dSmrg return true;
4101debfc3dSmrg }
4111debfc3dSmrg
4121debfc3dSmrg return false;
4131debfc3dSmrg }
4141debfc3dSmrg
4151debfc3dSmrg
4161debfc3dSmrg /* Compute __builtin_object_size for CALL, which is a GIMPLE_CALL.
417c0a68be4Smrg Handles calls to functions declared with attribute alloc_size.
418c0a68be4Smrg OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
419c0a68be4Smrg If unknown, return unknown[object_size_type]. */
4201debfc3dSmrg
4211debfc3dSmrg static unsigned HOST_WIDE_INT
alloc_object_size(const gcall * call,int object_size_type)4221debfc3dSmrg alloc_object_size (const gcall *call, int object_size_type)
4231debfc3dSmrg {
4241debfc3dSmrg gcc_assert (is_gimple_call (call));
4251debfc3dSmrg
426c0a68be4Smrg tree calltype;
427c0a68be4Smrg if (tree callfn = gimple_call_fndecl (call))
428c0a68be4Smrg calltype = TREE_TYPE (callfn);
429c0a68be4Smrg else
430c0a68be4Smrg calltype = gimple_call_fntype (call);
431c0a68be4Smrg
432c0a68be4Smrg if (!calltype)
4331debfc3dSmrg return unknown[object_size_type];
4341debfc3dSmrg
435c0a68be4Smrg /* Set to positions of alloc_size arguments. */
436c0a68be4Smrg int arg1 = -1, arg2 = -1;
437c0a68be4Smrg tree alloc_size = lookup_attribute ("alloc_size",
438c0a68be4Smrg TYPE_ATTRIBUTES (calltype));
4391debfc3dSmrg if (alloc_size && TREE_VALUE (alloc_size))
4401debfc3dSmrg {
4411debfc3dSmrg tree p = TREE_VALUE (alloc_size);
4421debfc3dSmrg
4431debfc3dSmrg arg1 = TREE_INT_CST_LOW (TREE_VALUE (p))-1;
4441debfc3dSmrg if (TREE_CHAIN (p))
4451debfc3dSmrg arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
4461debfc3dSmrg }
4471debfc3dSmrg
4481debfc3dSmrg if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call)
4491debfc3dSmrg || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST
4501debfc3dSmrg || (arg2 >= 0
4511debfc3dSmrg && (arg2 >= (int)gimple_call_num_args (call)
4521debfc3dSmrg || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST)))
4531debfc3dSmrg return unknown[object_size_type];
4541debfc3dSmrg
455c0a68be4Smrg tree bytes = NULL_TREE;
4561debfc3dSmrg if (arg2 >= 0)
4571debfc3dSmrg bytes = size_binop (MULT_EXPR,
4581debfc3dSmrg fold_convert (sizetype, gimple_call_arg (call, arg1)),
4591debfc3dSmrg fold_convert (sizetype, gimple_call_arg (call, arg2)));
4601debfc3dSmrg else if (arg1 >= 0)
4611debfc3dSmrg bytes = fold_convert (sizetype, gimple_call_arg (call, arg1));
4621debfc3dSmrg
4631debfc3dSmrg if (bytes && tree_fits_uhwi_p (bytes))
4641debfc3dSmrg return tree_to_uhwi (bytes);
4651debfc3dSmrg
4661debfc3dSmrg return unknown[object_size_type];
4671debfc3dSmrg }
4681debfc3dSmrg
4691debfc3dSmrg
4701debfc3dSmrg /* If object size is propagated from one of function's arguments directly
4711debfc3dSmrg to its return value, return that argument for GIMPLE_CALL statement CALL.
4721debfc3dSmrg Otherwise return NULL. */
4731debfc3dSmrg
4741debfc3dSmrg static tree
pass_through_call(const gcall * call)4751debfc3dSmrg pass_through_call (const gcall *call)
4761debfc3dSmrg {
477a2dc1f3fSmrg unsigned rf = gimple_call_return_flags (call);
478a2dc1f3fSmrg if (rf & ERF_RETURNS_ARG)
4791debfc3dSmrg {
480a2dc1f3fSmrg unsigned argnum = rf & ERF_RETURN_ARG_MASK;
481a2dc1f3fSmrg if (argnum < gimple_call_num_args (call))
482a2dc1f3fSmrg return gimple_call_arg (call, argnum);
4831debfc3dSmrg }
4841debfc3dSmrg
485a2dc1f3fSmrg /* __builtin_assume_aligned is intentionally not marked RET1. */
486a2dc1f3fSmrg if (gimple_call_builtin_p (call, BUILT_IN_ASSUME_ALIGNED))
487a2dc1f3fSmrg return gimple_call_arg (call, 0);
488a2dc1f3fSmrg
4891debfc3dSmrg return NULL_TREE;
4901debfc3dSmrg }
4911debfc3dSmrg
4921debfc3dSmrg
4931debfc3dSmrg /* Compute __builtin_object_size value for PTR and set *PSIZE to
494*8feb0f0bSmrg the resulting value. If the declared object is known and PDECL
495*8feb0f0bSmrg is nonnull, sets *PDECL to the object's DECL. OBJECT_SIZE_TYPE
496*8feb0f0bSmrg is the second argument to __builtin_object_size.
497*8feb0f0bSmrg Returns true on success and false when the object size could not
498*8feb0f0bSmrg be determined. */
4991debfc3dSmrg
5001debfc3dSmrg bool
compute_builtin_object_size(tree ptr,int object_size_type,unsigned HOST_WIDE_INT * psize,tree * pdecl,tree * poff)5011debfc3dSmrg compute_builtin_object_size (tree ptr, int object_size_type,
502*8feb0f0bSmrg unsigned HOST_WIDE_INT *psize,
503*8feb0f0bSmrg tree *pdecl /* = NULL */, tree *poff /* = NULL */)
5041debfc3dSmrg {
5051debfc3dSmrg gcc_assert (object_size_type >= 0 && object_size_type <= 3);
5061debfc3dSmrg
507*8feb0f0bSmrg tree dummy_decl, dummy_off = size_zero_node;
508*8feb0f0bSmrg if (!pdecl)
509*8feb0f0bSmrg pdecl = &dummy_decl;
510*8feb0f0bSmrg if (!poff)
511*8feb0f0bSmrg poff = &dummy_off;
512*8feb0f0bSmrg
5131debfc3dSmrg /* Set to unknown and overwrite just before returning if the size
5141debfc3dSmrg could be determined. */
5151debfc3dSmrg *psize = unknown[object_size_type];
5161debfc3dSmrg
5171debfc3dSmrg if (! offset_limit)
5181debfc3dSmrg init_offset_limit ();
5191debfc3dSmrg
5201debfc3dSmrg if (TREE_CODE (ptr) == ADDR_EXPR)
521*8feb0f0bSmrg return addr_object_size (NULL, ptr, object_size_type, psize, pdecl, poff);
5221debfc3dSmrg
5231debfc3dSmrg if (TREE_CODE (ptr) != SSA_NAME
5241debfc3dSmrg || !POINTER_TYPE_P (TREE_TYPE (ptr)))
5251debfc3dSmrg return false;
5261debfc3dSmrg
5271debfc3dSmrg if (computed[object_size_type] == NULL)
5281debfc3dSmrg {
5291debfc3dSmrg if (optimize || object_size_type & 1)
5301debfc3dSmrg return false;
5311debfc3dSmrg
5321debfc3dSmrg /* When not optimizing, rather than failing, make a small effort
5331debfc3dSmrg to determine the object size without the full benefit of
5341debfc3dSmrg the (costly) computation below. */
5351debfc3dSmrg gimple *def = SSA_NAME_DEF_STMT (ptr);
5361debfc3dSmrg if (gimple_code (def) == GIMPLE_ASSIGN)
5371debfc3dSmrg {
5381debfc3dSmrg tree_code code = gimple_assign_rhs_code (def);
5391debfc3dSmrg if (code == POINTER_PLUS_EXPR)
5401debfc3dSmrg {
5411debfc3dSmrg tree offset = gimple_assign_rhs2 (def);
5421debfc3dSmrg ptr = gimple_assign_rhs1 (def);
5431debfc3dSmrg
5441debfc3dSmrg if (tree_fits_shwi_p (offset)
545*8feb0f0bSmrg && compute_builtin_object_size (ptr, object_size_type,
546*8feb0f0bSmrg psize, pdecl, poff))
5471debfc3dSmrg {
5481debfc3dSmrg /* Return zero when the offset is out of bounds. */
5491debfc3dSmrg unsigned HOST_WIDE_INT off = tree_to_shwi (offset);
5501debfc3dSmrg *psize = off < *psize ? *psize - off : 0;
551*8feb0f0bSmrg *poff = offset;
5521debfc3dSmrg return true;
5531debfc3dSmrg }
5541debfc3dSmrg }
5551debfc3dSmrg }
5561debfc3dSmrg return false;
5571debfc3dSmrg }
5581debfc3dSmrg
5591debfc3dSmrg if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
5601debfc3dSmrg {
5611debfc3dSmrg struct object_size_info osi;
5621debfc3dSmrg bitmap_iterator bi;
5631debfc3dSmrg unsigned int i;
5641debfc3dSmrg
5651debfc3dSmrg if (num_ssa_names > object_sizes[object_size_type].length ())
5661debfc3dSmrg object_sizes[object_size_type].safe_grow (num_ssa_names);
5671debfc3dSmrg if (dump_file)
5681debfc3dSmrg {
5691debfc3dSmrg fprintf (dump_file, "Computing %s %sobject size for ",
5701debfc3dSmrg (object_size_type & 2) ? "minimum" : "maximum",
5711debfc3dSmrg (object_size_type & 1) ? "sub" : "");
5721debfc3dSmrg print_generic_expr (dump_file, ptr, dump_flags);
5731debfc3dSmrg fprintf (dump_file, ":\n");
5741debfc3dSmrg }
5751debfc3dSmrg
5761debfc3dSmrg osi.visited = BITMAP_ALLOC (NULL);
5771debfc3dSmrg osi.reexamine = BITMAP_ALLOC (NULL);
5781debfc3dSmrg osi.object_size_type = object_size_type;
5791debfc3dSmrg osi.depths = NULL;
5801debfc3dSmrg osi.stack = NULL;
5811debfc3dSmrg osi.tos = NULL;
5821debfc3dSmrg
5831debfc3dSmrg /* First pass: walk UD chains, compute object sizes that
5841debfc3dSmrg can be computed. osi.reexamine bitmap at the end will
5851debfc3dSmrg contain what variables were found in dependency cycles
5861debfc3dSmrg and therefore need to be reexamined. */
5871debfc3dSmrg osi.pass = 0;
5881debfc3dSmrg osi.changed = false;
5891debfc3dSmrg collect_object_sizes_for (&osi, ptr);
5901debfc3dSmrg
5911debfc3dSmrg /* Second pass: keep recomputing object sizes of variables
5921debfc3dSmrg that need reexamination, until no object sizes are
5931debfc3dSmrg increased or all object sizes are computed. */
5941debfc3dSmrg if (! bitmap_empty_p (osi.reexamine))
5951debfc3dSmrg {
5961debfc3dSmrg bitmap reexamine = BITMAP_ALLOC (NULL);
5971debfc3dSmrg
5981debfc3dSmrg /* If looking for minimum instead of maximum object size,
5991debfc3dSmrg detect cases where a pointer is increased in a loop.
6001debfc3dSmrg Although even without this detection pass 2 would eventually
6011debfc3dSmrg terminate, it could take a long time. If a pointer is
6021debfc3dSmrg increasing this way, we need to assume 0 object size.
6031debfc3dSmrg E.g. p = &buf[0]; while (cond) p = p + 4; */
6041debfc3dSmrg if (object_size_type & 2)
6051debfc3dSmrg {
6061debfc3dSmrg osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
6071debfc3dSmrg osi.stack = XNEWVEC (unsigned int, num_ssa_names);
6081debfc3dSmrg osi.tos = osi.stack;
6091debfc3dSmrg osi.pass = 1;
6101debfc3dSmrg /* collect_object_sizes_for is changing
6111debfc3dSmrg osi.reexamine bitmap, so iterate over a copy. */
6121debfc3dSmrg bitmap_copy (reexamine, osi.reexamine);
6131debfc3dSmrg EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
6141debfc3dSmrg if (bitmap_bit_p (osi.reexamine, i))
6151debfc3dSmrg check_for_plus_in_loops (&osi, ssa_name (i));
6161debfc3dSmrg
6171debfc3dSmrg free (osi.depths);
6181debfc3dSmrg osi.depths = NULL;
6191debfc3dSmrg free (osi.stack);
6201debfc3dSmrg osi.stack = NULL;
6211debfc3dSmrg osi.tos = NULL;
6221debfc3dSmrg }
6231debfc3dSmrg
6241debfc3dSmrg do
6251debfc3dSmrg {
6261debfc3dSmrg osi.pass = 2;
6271debfc3dSmrg osi.changed = false;
6281debfc3dSmrg /* collect_object_sizes_for is changing
6291debfc3dSmrg osi.reexamine bitmap, so iterate over a copy. */
6301debfc3dSmrg bitmap_copy (reexamine, osi.reexamine);
6311debfc3dSmrg EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
6321debfc3dSmrg if (bitmap_bit_p (osi.reexamine, i))
6331debfc3dSmrg {
6341debfc3dSmrg collect_object_sizes_for (&osi, ssa_name (i));
6351debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6361debfc3dSmrg {
6371debfc3dSmrg fprintf (dump_file, "Reexamining ");
6381debfc3dSmrg print_generic_expr (dump_file, ssa_name (i),
6391debfc3dSmrg dump_flags);
6401debfc3dSmrg fprintf (dump_file, "\n");
6411debfc3dSmrg }
6421debfc3dSmrg }
6431debfc3dSmrg }
6441debfc3dSmrg while (osi.changed);
6451debfc3dSmrg
6461debfc3dSmrg BITMAP_FREE (reexamine);
6471debfc3dSmrg }
6481debfc3dSmrg EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
6491debfc3dSmrg bitmap_set_bit (computed[object_size_type], i);
6501debfc3dSmrg
6511debfc3dSmrg /* Debugging dumps. */
6521debfc3dSmrg if (dump_file)
6531debfc3dSmrg {
6541debfc3dSmrg EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
6551debfc3dSmrg if (object_sizes[object_size_type][i]
6561debfc3dSmrg != unknown[object_size_type])
6571debfc3dSmrg {
6581debfc3dSmrg print_generic_expr (dump_file, ssa_name (i),
6591debfc3dSmrg dump_flags);
6601debfc3dSmrg fprintf (dump_file,
6611debfc3dSmrg ": %s %sobject size "
6621debfc3dSmrg HOST_WIDE_INT_PRINT_UNSIGNED "\n",
6631debfc3dSmrg (object_size_type & 2) ? "minimum" : "maximum",
6641debfc3dSmrg (object_size_type & 1) ? "sub" : "",
6651debfc3dSmrg object_sizes[object_size_type][i]);
6661debfc3dSmrg }
6671debfc3dSmrg }
6681debfc3dSmrg
6691debfc3dSmrg BITMAP_FREE (osi.reexamine);
6701debfc3dSmrg BITMAP_FREE (osi.visited);
6711debfc3dSmrg }
6721debfc3dSmrg
6731debfc3dSmrg *psize = object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
6741debfc3dSmrg return *psize != unknown[object_size_type];
6751debfc3dSmrg }
6761debfc3dSmrg
6771debfc3dSmrg /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */
6781debfc3dSmrg
6791debfc3dSmrg static void
expr_object_size(struct object_size_info * osi,tree ptr,tree value)6801debfc3dSmrg expr_object_size (struct object_size_info *osi, tree ptr, tree value)
6811debfc3dSmrg {
6821debfc3dSmrg int object_size_type = osi->object_size_type;
6831debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (ptr);
6841debfc3dSmrg unsigned HOST_WIDE_INT bytes;
6851debfc3dSmrg
6861debfc3dSmrg gcc_assert (object_sizes[object_size_type][varno]
6871debfc3dSmrg != unknown[object_size_type]);
6881debfc3dSmrg gcc_assert (osi->pass == 0);
6891debfc3dSmrg
6901debfc3dSmrg if (TREE_CODE (value) == WITH_SIZE_EXPR)
6911debfc3dSmrg value = TREE_OPERAND (value, 0);
6921debfc3dSmrg
6931debfc3dSmrg /* Pointer variables should have been handled by merge_object_sizes. */
6941debfc3dSmrg gcc_assert (TREE_CODE (value) != SSA_NAME
6951debfc3dSmrg || !POINTER_TYPE_P (TREE_TYPE (value)));
6961debfc3dSmrg
6971debfc3dSmrg if (TREE_CODE (value) == ADDR_EXPR)
6981debfc3dSmrg addr_object_size (osi, value, object_size_type, &bytes);
6991debfc3dSmrg else
7001debfc3dSmrg bytes = unknown[object_size_type];
7011debfc3dSmrg
7021debfc3dSmrg if ((object_size_type & 2) == 0)
7031debfc3dSmrg {
7041debfc3dSmrg if (object_sizes[object_size_type][varno] < bytes)
7051debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
7061debfc3dSmrg }
7071debfc3dSmrg else
7081debfc3dSmrg {
7091debfc3dSmrg if (object_sizes[object_size_type][varno] > bytes)
7101debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
7111debfc3dSmrg }
7121debfc3dSmrg }
7131debfc3dSmrg
7141debfc3dSmrg
7151debfc3dSmrg /* Compute object_sizes for PTR, defined to the result of a call. */
7161debfc3dSmrg
7171debfc3dSmrg static void
call_object_size(struct object_size_info * osi,tree ptr,gcall * call)7181debfc3dSmrg call_object_size (struct object_size_info *osi, tree ptr, gcall *call)
7191debfc3dSmrg {
7201debfc3dSmrg int object_size_type = osi->object_size_type;
7211debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (ptr);
7221debfc3dSmrg unsigned HOST_WIDE_INT bytes;
7231debfc3dSmrg
7241debfc3dSmrg gcc_assert (is_gimple_call (call));
7251debfc3dSmrg
7261debfc3dSmrg gcc_assert (object_sizes[object_size_type][varno]
7271debfc3dSmrg != unknown[object_size_type]);
7281debfc3dSmrg gcc_assert (osi->pass == 0);
7291debfc3dSmrg
7301debfc3dSmrg bytes = alloc_object_size (call, object_size_type);
7311debfc3dSmrg
7321debfc3dSmrg if ((object_size_type & 2) == 0)
7331debfc3dSmrg {
7341debfc3dSmrg if (object_sizes[object_size_type][varno] < bytes)
7351debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
7361debfc3dSmrg }
7371debfc3dSmrg else
7381debfc3dSmrg {
7391debfc3dSmrg if (object_sizes[object_size_type][varno] > bytes)
7401debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
7411debfc3dSmrg }
7421debfc3dSmrg }
7431debfc3dSmrg
7441debfc3dSmrg
7451debfc3dSmrg /* Compute object_sizes for PTR, defined to an unknown value. */
7461debfc3dSmrg
7471debfc3dSmrg static void
unknown_object_size(struct object_size_info * osi,tree ptr)7481debfc3dSmrg unknown_object_size (struct object_size_info *osi, tree ptr)
7491debfc3dSmrg {
7501debfc3dSmrg int object_size_type = osi->object_size_type;
7511debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (ptr);
7521debfc3dSmrg unsigned HOST_WIDE_INT bytes;
7531debfc3dSmrg
7541debfc3dSmrg gcc_assert (object_sizes[object_size_type][varno]
7551debfc3dSmrg != unknown[object_size_type]);
7561debfc3dSmrg gcc_assert (osi->pass == 0);
7571debfc3dSmrg
7581debfc3dSmrg bytes = unknown[object_size_type];
7591debfc3dSmrg
7601debfc3dSmrg if ((object_size_type & 2) == 0)
7611debfc3dSmrg {
7621debfc3dSmrg if (object_sizes[object_size_type][varno] < bytes)
7631debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
7641debfc3dSmrg }
7651debfc3dSmrg else
7661debfc3dSmrg {
7671debfc3dSmrg if (object_sizes[object_size_type][varno] > bytes)
7681debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
7691debfc3dSmrg }
7701debfc3dSmrg }
7711debfc3dSmrg
7721debfc3dSmrg
7731debfc3dSmrg /* Merge object sizes of ORIG + OFFSET into DEST. Return true if
7741debfc3dSmrg the object size might need reexamination later. */
7751debfc3dSmrg
7761debfc3dSmrg static bool
merge_object_sizes(struct object_size_info * osi,tree dest,tree orig,unsigned HOST_WIDE_INT offset)7771debfc3dSmrg merge_object_sizes (struct object_size_info *osi, tree dest, tree orig,
7781debfc3dSmrg unsigned HOST_WIDE_INT offset)
7791debfc3dSmrg {
7801debfc3dSmrg int object_size_type = osi->object_size_type;
7811debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (dest);
7821debfc3dSmrg unsigned HOST_WIDE_INT orig_bytes;
7831debfc3dSmrg
7841debfc3dSmrg if (object_sizes[object_size_type][varno] == unknown[object_size_type])
7851debfc3dSmrg return false;
7861debfc3dSmrg if (offset >= offset_limit)
7871debfc3dSmrg {
7881debfc3dSmrg object_sizes[object_size_type][varno] = unknown[object_size_type];
7891debfc3dSmrg return false;
7901debfc3dSmrg }
7911debfc3dSmrg
7921debfc3dSmrg if (osi->pass == 0)
7931debfc3dSmrg collect_object_sizes_for (osi, orig);
7941debfc3dSmrg
7951debfc3dSmrg orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)];
7961debfc3dSmrg if (orig_bytes != unknown[object_size_type])
7971debfc3dSmrg orig_bytes = (offset > orig_bytes)
7981debfc3dSmrg ? HOST_WIDE_INT_0U : orig_bytes - offset;
7991debfc3dSmrg
8001debfc3dSmrg if ((object_size_type & 2) == 0)
8011debfc3dSmrg {
8021debfc3dSmrg if (object_sizes[object_size_type][varno] < orig_bytes)
8031debfc3dSmrg {
8041debfc3dSmrg object_sizes[object_size_type][varno] = orig_bytes;
8051debfc3dSmrg osi->changed = true;
8061debfc3dSmrg }
8071debfc3dSmrg }
8081debfc3dSmrg else
8091debfc3dSmrg {
8101debfc3dSmrg if (object_sizes[object_size_type][varno] > orig_bytes)
8111debfc3dSmrg {
8121debfc3dSmrg object_sizes[object_size_type][varno] = orig_bytes;
8131debfc3dSmrg osi->changed = true;
8141debfc3dSmrg }
8151debfc3dSmrg }
8161debfc3dSmrg return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
8171debfc3dSmrg }
8181debfc3dSmrg
8191debfc3dSmrg
8201debfc3dSmrg /* Compute object_sizes for VAR, defined to the result of an assignment
8211debfc3dSmrg with operator POINTER_PLUS_EXPR. Return true if the object size might
8221debfc3dSmrg need reexamination later. */
8231debfc3dSmrg
8241debfc3dSmrg static bool
plus_stmt_object_size(struct object_size_info * osi,tree var,gimple * stmt)8251debfc3dSmrg plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt)
8261debfc3dSmrg {
8271debfc3dSmrg int object_size_type = osi->object_size_type;
8281debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (var);
8291debfc3dSmrg unsigned HOST_WIDE_INT bytes;
8301debfc3dSmrg tree op0, op1;
8311debfc3dSmrg
8321debfc3dSmrg if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
8331debfc3dSmrg {
8341debfc3dSmrg op0 = gimple_assign_rhs1 (stmt);
8351debfc3dSmrg op1 = gimple_assign_rhs2 (stmt);
8361debfc3dSmrg }
8371debfc3dSmrg else if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
8381debfc3dSmrg {
8391debfc3dSmrg tree rhs = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
8401debfc3dSmrg gcc_assert (TREE_CODE (rhs) == MEM_REF);
8411debfc3dSmrg op0 = TREE_OPERAND (rhs, 0);
8421debfc3dSmrg op1 = TREE_OPERAND (rhs, 1);
8431debfc3dSmrg }
8441debfc3dSmrg else
8451debfc3dSmrg gcc_unreachable ();
8461debfc3dSmrg
8471debfc3dSmrg if (object_sizes[object_size_type][varno] == unknown[object_size_type])
8481debfc3dSmrg return false;
8491debfc3dSmrg
8501debfc3dSmrg /* Handle PTR + OFFSET here. */
8511debfc3dSmrg if (TREE_CODE (op1) == INTEGER_CST
8521debfc3dSmrg && (TREE_CODE (op0) == SSA_NAME
8531debfc3dSmrg || TREE_CODE (op0) == ADDR_EXPR))
8541debfc3dSmrg {
8551debfc3dSmrg if (! tree_fits_uhwi_p (op1))
8561debfc3dSmrg bytes = unknown[object_size_type];
8571debfc3dSmrg else if (TREE_CODE (op0) == SSA_NAME)
8581debfc3dSmrg return merge_object_sizes (osi, var, op0, tree_to_uhwi (op1));
8591debfc3dSmrg else
8601debfc3dSmrg {
8611debfc3dSmrg unsigned HOST_WIDE_INT off = tree_to_uhwi (op1);
8621debfc3dSmrg
8631debfc3dSmrg /* op0 will be ADDR_EXPR here. */
8641debfc3dSmrg addr_object_size (osi, op0, object_size_type, &bytes);
8651debfc3dSmrg if (bytes == unknown[object_size_type])
8661debfc3dSmrg ;
8671debfc3dSmrg else if (off > offset_limit)
8681debfc3dSmrg bytes = unknown[object_size_type];
8691debfc3dSmrg else if (off > bytes)
8701debfc3dSmrg bytes = 0;
8711debfc3dSmrg else
8721debfc3dSmrg bytes -= off;
8731debfc3dSmrg }
8741debfc3dSmrg }
8751debfc3dSmrg else
8761debfc3dSmrg bytes = unknown[object_size_type];
8771debfc3dSmrg
8781debfc3dSmrg if ((object_size_type & 2) == 0)
8791debfc3dSmrg {
8801debfc3dSmrg if (object_sizes[object_size_type][varno] < bytes)
8811debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
8821debfc3dSmrg }
8831debfc3dSmrg else
8841debfc3dSmrg {
8851debfc3dSmrg if (object_sizes[object_size_type][varno] > bytes)
8861debfc3dSmrg object_sizes[object_size_type][varno] = bytes;
8871debfc3dSmrg }
8881debfc3dSmrg return false;
8891debfc3dSmrg }
8901debfc3dSmrg
8911debfc3dSmrg
8921debfc3dSmrg /* Compute object_sizes for VAR, defined at STMT, which is
8931debfc3dSmrg a COND_EXPR. Return true if the object size might need reexamination
8941debfc3dSmrg later. */
8951debfc3dSmrg
8961debfc3dSmrg static bool
cond_expr_object_size(struct object_size_info * osi,tree var,gimple * stmt)8971debfc3dSmrg cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt)
8981debfc3dSmrg {
8991debfc3dSmrg tree then_, else_;
9001debfc3dSmrg int object_size_type = osi->object_size_type;
9011debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (var);
9021debfc3dSmrg bool reexamine = false;
9031debfc3dSmrg
9041debfc3dSmrg gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR);
9051debfc3dSmrg
9061debfc3dSmrg if (object_sizes[object_size_type][varno] == unknown[object_size_type])
9071debfc3dSmrg return false;
9081debfc3dSmrg
9091debfc3dSmrg then_ = gimple_assign_rhs2 (stmt);
9101debfc3dSmrg else_ = gimple_assign_rhs3 (stmt);
9111debfc3dSmrg
9121debfc3dSmrg if (TREE_CODE (then_) == SSA_NAME)
9131debfc3dSmrg reexamine |= merge_object_sizes (osi, var, then_, 0);
9141debfc3dSmrg else
9151debfc3dSmrg expr_object_size (osi, var, then_);
9161debfc3dSmrg
917a2dc1f3fSmrg if (object_sizes[object_size_type][varno] == unknown[object_size_type])
918a2dc1f3fSmrg return reexamine;
919a2dc1f3fSmrg
9201debfc3dSmrg if (TREE_CODE (else_) == SSA_NAME)
9211debfc3dSmrg reexamine |= merge_object_sizes (osi, var, else_, 0);
9221debfc3dSmrg else
9231debfc3dSmrg expr_object_size (osi, var, else_);
9241debfc3dSmrg
9251debfc3dSmrg return reexamine;
9261debfc3dSmrg }
9271debfc3dSmrg
9281debfc3dSmrg /* Compute object sizes for VAR.
9291debfc3dSmrg For ADDR_EXPR an object size is the number of remaining bytes
9301debfc3dSmrg to the end of the object (where what is considered an object depends on
9311debfc3dSmrg OSI->object_size_type).
9321debfc3dSmrg For allocation GIMPLE_CALL like malloc or calloc object size is the size
9331debfc3dSmrg of the allocation.
9341debfc3dSmrg For POINTER_PLUS_EXPR where second operand is a constant integer,
9351debfc3dSmrg object size is object size of the first operand minus the constant.
9361debfc3dSmrg If the constant is bigger than the number of remaining bytes until the
9371debfc3dSmrg end of the object, object size is 0, but if it is instead a pointer
9381debfc3dSmrg subtraction, object size is unknown[object_size_type].
9391debfc3dSmrg To differentiate addition from subtraction, ADDR_EXPR returns
9401debfc3dSmrg unknown[object_size_type] for all objects bigger than half of the address
9411debfc3dSmrg space, and constants less than half of the address space are considered
9421debfc3dSmrg addition, while bigger constants subtraction.
9431debfc3dSmrg For a memcpy like GIMPLE_CALL that always returns one of its arguments, the
9441debfc3dSmrg object size is object size of that argument.
9451debfc3dSmrg Otherwise, object size is the maximum of object sizes of variables
9461debfc3dSmrg that it might be set to. */
9471debfc3dSmrg
9481debfc3dSmrg static void
collect_object_sizes_for(struct object_size_info * osi,tree var)9491debfc3dSmrg collect_object_sizes_for (struct object_size_info *osi, tree var)
9501debfc3dSmrg {
9511debfc3dSmrg int object_size_type = osi->object_size_type;
9521debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (var);
9531debfc3dSmrg gimple *stmt;
9541debfc3dSmrg bool reexamine;
9551debfc3dSmrg
9561debfc3dSmrg if (bitmap_bit_p (computed[object_size_type], varno))
9571debfc3dSmrg return;
9581debfc3dSmrg
9591debfc3dSmrg if (osi->pass == 0)
9601debfc3dSmrg {
9611debfc3dSmrg if (bitmap_set_bit (osi->visited, varno))
9621debfc3dSmrg {
9631debfc3dSmrg object_sizes[object_size_type][varno]
9641debfc3dSmrg = (object_size_type & 2) ? -1 : 0;
9651debfc3dSmrg }
9661debfc3dSmrg else
9671debfc3dSmrg {
9681debfc3dSmrg /* Found a dependency loop. Mark the variable for later
9691debfc3dSmrg re-examination. */
9701debfc3dSmrg bitmap_set_bit (osi->reexamine, varno);
9711debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
9721debfc3dSmrg {
9731debfc3dSmrg fprintf (dump_file, "Found a dependency loop at ");
9741debfc3dSmrg print_generic_expr (dump_file, var, dump_flags);
9751debfc3dSmrg fprintf (dump_file, "\n");
9761debfc3dSmrg }
9771debfc3dSmrg return;
9781debfc3dSmrg }
9791debfc3dSmrg }
9801debfc3dSmrg
9811debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
9821debfc3dSmrg {
9831debfc3dSmrg fprintf (dump_file, "Visiting use-def links for ");
9841debfc3dSmrg print_generic_expr (dump_file, var, dump_flags);
9851debfc3dSmrg fprintf (dump_file, "\n");
9861debfc3dSmrg }
9871debfc3dSmrg
9881debfc3dSmrg stmt = SSA_NAME_DEF_STMT (var);
9891debfc3dSmrg reexamine = false;
9901debfc3dSmrg
9911debfc3dSmrg switch (gimple_code (stmt))
9921debfc3dSmrg {
9931debfc3dSmrg case GIMPLE_ASSIGN:
9941debfc3dSmrg {
9951debfc3dSmrg tree rhs = gimple_assign_rhs1 (stmt);
9961debfc3dSmrg if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
9971debfc3dSmrg || (gimple_assign_rhs_code (stmt) == ADDR_EXPR
9981debfc3dSmrg && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF))
9991debfc3dSmrg reexamine = plus_stmt_object_size (osi, var, stmt);
10001debfc3dSmrg else if (gimple_assign_rhs_code (stmt) == COND_EXPR)
10011debfc3dSmrg reexamine = cond_expr_object_size (osi, var, stmt);
10021debfc3dSmrg else if (gimple_assign_single_p (stmt)
10031debfc3dSmrg || gimple_assign_unary_nop_p (stmt))
10041debfc3dSmrg {
10051debfc3dSmrg if (TREE_CODE (rhs) == SSA_NAME
10061debfc3dSmrg && POINTER_TYPE_P (TREE_TYPE (rhs)))
10071debfc3dSmrg reexamine = merge_object_sizes (osi, var, rhs, 0);
10081debfc3dSmrg else
10091debfc3dSmrg expr_object_size (osi, var, rhs);
10101debfc3dSmrg }
10111debfc3dSmrg else
10121debfc3dSmrg unknown_object_size (osi, var);
10131debfc3dSmrg break;
10141debfc3dSmrg }
10151debfc3dSmrg
10161debfc3dSmrg case GIMPLE_CALL:
10171debfc3dSmrg {
10181debfc3dSmrg gcall *call_stmt = as_a <gcall *> (stmt);
10191debfc3dSmrg tree arg = pass_through_call (call_stmt);
10201debfc3dSmrg if (arg)
10211debfc3dSmrg {
10221debfc3dSmrg if (TREE_CODE (arg) == SSA_NAME
10231debfc3dSmrg && POINTER_TYPE_P (TREE_TYPE (arg)))
10241debfc3dSmrg reexamine = merge_object_sizes (osi, var, arg, 0);
10251debfc3dSmrg else
10261debfc3dSmrg expr_object_size (osi, var, arg);
10271debfc3dSmrg }
10281debfc3dSmrg else
10291debfc3dSmrg call_object_size (osi, var, call_stmt);
10301debfc3dSmrg break;
10311debfc3dSmrg }
10321debfc3dSmrg
10331debfc3dSmrg case GIMPLE_ASM:
10341debfc3dSmrg /* Pointers defined by __asm__ statements can point anywhere. */
10351debfc3dSmrg object_sizes[object_size_type][varno] = unknown[object_size_type];
10361debfc3dSmrg break;
10371debfc3dSmrg
10381debfc3dSmrg case GIMPLE_NOP:
10391debfc3dSmrg if (SSA_NAME_VAR (var)
10401debfc3dSmrg && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL)
10411debfc3dSmrg expr_object_size (osi, var, SSA_NAME_VAR (var));
10421debfc3dSmrg else
10431debfc3dSmrg /* Uninitialized SSA names point nowhere. */
10441debfc3dSmrg object_sizes[object_size_type][varno] = unknown[object_size_type];
10451debfc3dSmrg break;
10461debfc3dSmrg
10471debfc3dSmrg case GIMPLE_PHI:
10481debfc3dSmrg {
10491debfc3dSmrg unsigned i;
10501debfc3dSmrg
10511debfc3dSmrg for (i = 0; i < gimple_phi_num_args (stmt); i++)
10521debfc3dSmrg {
10531debfc3dSmrg tree rhs = gimple_phi_arg (stmt, i)->def;
10541debfc3dSmrg
10551debfc3dSmrg if (object_sizes[object_size_type][varno]
10561debfc3dSmrg == unknown[object_size_type])
10571debfc3dSmrg break;
10581debfc3dSmrg
10591debfc3dSmrg if (TREE_CODE (rhs) == SSA_NAME)
10601debfc3dSmrg reexamine |= merge_object_sizes (osi, var, rhs, 0);
10611debfc3dSmrg else if (osi->pass == 0)
10621debfc3dSmrg expr_object_size (osi, var, rhs);
10631debfc3dSmrg }
10641debfc3dSmrg break;
10651debfc3dSmrg }
10661debfc3dSmrg
10671debfc3dSmrg default:
10681debfc3dSmrg gcc_unreachable ();
10691debfc3dSmrg }
10701debfc3dSmrg
10711debfc3dSmrg if (! reexamine
10721debfc3dSmrg || object_sizes[object_size_type][varno] == unknown[object_size_type])
10731debfc3dSmrg {
10741debfc3dSmrg bitmap_set_bit (computed[object_size_type], varno);
10751debfc3dSmrg bitmap_clear_bit (osi->reexamine, varno);
10761debfc3dSmrg }
10771debfc3dSmrg else
10781debfc3dSmrg {
10791debfc3dSmrg bitmap_set_bit (osi->reexamine, varno);
10801debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
10811debfc3dSmrg {
10821debfc3dSmrg fprintf (dump_file, "Need to reexamine ");
10831debfc3dSmrg print_generic_expr (dump_file, var, dump_flags);
10841debfc3dSmrg fprintf (dump_file, "\n");
10851debfc3dSmrg }
10861debfc3dSmrg }
10871debfc3dSmrg }
10881debfc3dSmrg
10891debfc3dSmrg
10901debfc3dSmrg /* Helper function for check_for_plus_in_loops. Called recursively
10911debfc3dSmrg to detect loops. */
10921debfc3dSmrg
10931debfc3dSmrg static void
check_for_plus_in_loops_1(struct object_size_info * osi,tree var,unsigned int depth)10941debfc3dSmrg check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
10951debfc3dSmrg unsigned int depth)
10961debfc3dSmrg {
10971debfc3dSmrg gimple *stmt = SSA_NAME_DEF_STMT (var);
10981debfc3dSmrg unsigned int varno = SSA_NAME_VERSION (var);
10991debfc3dSmrg
11001debfc3dSmrg if (osi->depths[varno])
11011debfc3dSmrg {
11021debfc3dSmrg if (osi->depths[varno] != depth)
11031debfc3dSmrg {
11041debfc3dSmrg unsigned int *sp;
11051debfc3dSmrg
11061debfc3dSmrg /* Found a loop involving pointer addition. */
11071debfc3dSmrg for (sp = osi->tos; sp > osi->stack; )
11081debfc3dSmrg {
11091debfc3dSmrg --sp;
11101debfc3dSmrg bitmap_clear_bit (osi->reexamine, *sp);
11111debfc3dSmrg bitmap_set_bit (computed[osi->object_size_type], *sp);
11121debfc3dSmrg object_sizes[osi->object_size_type][*sp] = 0;
11131debfc3dSmrg if (*sp == varno)
11141debfc3dSmrg break;
11151debfc3dSmrg }
11161debfc3dSmrg }
11171debfc3dSmrg return;
11181debfc3dSmrg }
11191debfc3dSmrg else if (! bitmap_bit_p (osi->reexamine, varno))
11201debfc3dSmrg return;
11211debfc3dSmrg
11221debfc3dSmrg osi->depths[varno] = depth;
11231debfc3dSmrg *osi->tos++ = varno;
11241debfc3dSmrg
11251debfc3dSmrg switch (gimple_code (stmt))
11261debfc3dSmrg {
11271debfc3dSmrg
11281debfc3dSmrg case GIMPLE_ASSIGN:
11291debfc3dSmrg {
11301debfc3dSmrg if ((gimple_assign_single_p (stmt)
11311debfc3dSmrg || gimple_assign_unary_nop_p (stmt))
11321debfc3dSmrg && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
11331debfc3dSmrg {
11341debfc3dSmrg tree rhs = gimple_assign_rhs1 (stmt);
11351debfc3dSmrg
11361debfc3dSmrg check_for_plus_in_loops_1 (osi, rhs, depth);
11371debfc3dSmrg }
11381debfc3dSmrg else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
11391debfc3dSmrg {
11401debfc3dSmrg tree basevar = gimple_assign_rhs1 (stmt);
11411debfc3dSmrg tree cst = gimple_assign_rhs2 (stmt);
11421debfc3dSmrg
11431debfc3dSmrg gcc_assert (TREE_CODE (cst) == INTEGER_CST);
11441debfc3dSmrg
11451debfc3dSmrg check_for_plus_in_loops_1 (osi, basevar,
11461debfc3dSmrg depth + !integer_zerop (cst));
11471debfc3dSmrg }
11481debfc3dSmrg else
11491debfc3dSmrg gcc_unreachable ();
11501debfc3dSmrg break;
11511debfc3dSmrg }
11521debfc3dSmrg
11531debfc3dSmrg case GIMPLE_CALL:
11541debfc3dSmrg {
11551debfc3dSmrg gcall *call_stmt = as_a <gcall *> (stmt);
11561debfc3dSmrg tree arg = pass_through_call (call_stmt);
11571debfc3dSmrg if (arg)
11581debfc3dSmrg {
11591debfc3dSmrg if (TREE_CODE (arg) == SSA_NAME)
11601debfc3dSmrg check_for_plus_in_loops_1 (osi, arg, depth);
11611debfc3dSmrg else
11621debfc3dSmrg gcc_unreachable ();
11631debfc3dSmrg }
11641debfc3dSmrg break;
11651debfc3dSmrg }
11661debfc3dSmrg
11671debfc3dSmrg case GIMPLE_PHI:
11681debfc3dSmrg {
11691debfc3dSmrg unsigned i;
11701debfc3dSmrg
11711debfc3dSmrg for (i = 0; i < gimple_phi_num_args (stmt); i++)
11721debfc3dSmrg {
11731debfc3dSmrg tree rhs = gimple_phi_arg (stmt, i)->def;
11741debfc3dSmrg
11751debfc3dSmrg if (TREE_CODE (rhs) == SSA_NAME)
11761debfc3dSmrg check_for_plus_in_loops_1 (osi, rhs, depth);
11771debfc3dSmrg }
11781debfc3dSmrg break;
11791debfc3dSmrg }
11801debfc3dSmrg
11811debfc3dSmrg default:
11821debfc3dSmrg gcc_unreachable ();
11831debfc3dSmrg }
11841debfc3dSmrg
11851debfc3dSmrg osi->depths[varno] = 0;
11861debfc3dSmrg osi->tos--;
11871debfc3dSmrg }
11881debfc3dSmrg
11891debfc3dSmrg
11901debfc3dSmrg /* Check if some pointer we are computing object size of is being increased
11911debfc3dSmrg within a loop. If yes, assume all the SSA variables participating in
11921debfc3dSmrg that loop have minimum object sizes 0. */
11931debfc3dSmrg
11941debfc3dSmrg static void
check_for_plus_in_loops(struct object_size_info * osi,tree var)11951debfc3dSmrg check_for_plus_in_loops (struct object_size_info *osi, tree var)
11961debfc3dSmrg {
11971debfc3dSmrg gimple *stmt = SSA_NAME_DEF_STMT (var);
11981debfc3dSmrg
11991debfc3dSmrg /* NOTE: In the pre-tuples code, we handled a CALL_EXPR here,
12001debfc3dSmrg and looked for a POINTER_PLUS_EXPR in the pass-through
12011debfc3dSmrg argument, if any. In GIMPLE, however, such an expression
12021debfc3dSmrg is not a valid call operand. */
12031debfc3dSmrg
12041debfc3dSmrg if (is_gimple_assign (stmt)
12051debfc3dSmrg && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
12061debfc3dSmrg {
12071debfc3dSmrg tree basevar = gimple_assign_rhs1 (stmt);
12081debfc3dSmrg tree cst = gimple_assign_rhs2 (stmt);
12091debfc3dSmrg
12101debfc3dSmrg gcc_assert (TREE_CODE (cst) == INTEGER_CST);
12111debfc3dSmrg
12121debfc3dSmrg if (integer_zerop (cst))
12131debfc3dSmrg return;
12141debfc3dSmrg
12151debfc3dSmrg osi->depths[SSA_NAME_VERSION (basevar)] = 1;
12161debfc3dSmrg *osi->tos++ = SSA_NAME_VERSION (basevar);
12171debfc3dSmrg check_for_plus_in_loops_1 (osi, var, 2);
12181debfc3dSmrg osi->depths[SSA_NAME_VERSION (basevar)] = 0;
12191debfc3dSmrg osi->tos--;
12201debfc3dSmrg }
12211debfc3dSmrg }
12221debfc3dSmrg
12231debfc3dSmrg
12241debfc3dSmrg /* Initialize data structures for the object size computation. */
12251debfc3dSmrg
12261debfc3dSmrg void
init_object_sizes(void)12271debfc3dSmrg init_object_sizes (void)
12281debfc3dSmrg {
12291debfc3dSmrg int object_size_type;
12301debfc3dSmrg
12311debfc3dSmrg if (computed[0])
12321debfc3dSmrg return;
12331debfc3dSmrg
12341debfc3dSmrg for (object_size_type = 0; object_size_type <= 3; object_size_type++)
12351debfc3dSmrg {
12361debfc3dSmrg object_sizes[object_size_type].safe_grow (num_ssa_names);
12371debfc3dSmrg computed[object_size_type] = BITMAP_ALLOC (NULL);
12381debfc3dSmrg }
12391debfc3dSmrg
12401debfc3dSmrg init_offset_limit ();
12411debfc3dSmrg }
12421debfc3dSmrg
12431debfc3dSmrg
12441debfc3dSmrg /* Destroy data structures after the object size computation. */
12451debfc3dSmrg
12461debfc3dSmrg void
fini_object_sizes(void)12471debfc3dSmrg fini_object_sizes (void)
12481debfc3dSmrg {
12491debfc3dSmrg int object_size_type;
12501debfc3dSmrg
12511debfc3dSmrg for (object_size_type = 0; object_size_type <= 3; object_size_type++)
12521debfc3dSmrg {
12531debfc3dSmrg object_sizes[object_size_type].release ();
12541debfc3dSmrg BITMAP_FREE (computed[object_size_type]);
12551debfc3dSmrg }
12561debfc3dSmrg }
12571debfc3dSmrg
12581debfc3dSmrg
12591debfc3dSmrg /* Simple pass to optimize all __builtin_object_size () builtins. */
12601debfc3dSmrg
12611debfc3dSmrg namespace {
12621debfc3dSmrg
12631debfc3dSmrg const pass_data pass_data_object_sizes =
12641debfc3dSmrg {
12651debfc3dSmrg GIMPLE_PASS, /* type */
12661debfc3dSmrg "objsz", /* name */
12671debfc3dSmrg OPTGROUP_NONE, /* optinfo_flags */
12681debfc3dSmrg TV_NONE, /* tv_id */
12691debfc3dSmrg ( PROP_cfg | PROP_ssa ), /* properties_required */
12701debfc3dSmrg 0, /* properties_provided */
12711debfc3dSmrg 0, /* properties_destroyed */
12721debfc3dSmrg 0, /* todo_flags_start */
12731debfc3dSmrg 0, /* todo_flags_finish */
12741debfc3dSmrg };
12751debfc3dSmrg
12761debfc3dSmrg class pass_object_sizes : public gimple_opt_pass
12771debfc3dSmrg {
12781debfc3dSmrg public:
pass_object_sizes(gcc::context * ctxt)12791debfc3dSmrg pass_object_sizes (gcc::context *ctxt)
12801debfc3dSmrg : gimple_opt_pass (pass_data_object_sizes, ctxt), insert_min_max_p (false)
12811debfc3dSmrg {}
12821debfc3dSmrg
12831debfc3dSmrg /* opt_pass methods: */
clone()12841debfc3dSmrg opt_pass * clone () { return new pass_object_sizes (m_ctxt); }
set_pass_param(unsigned int n,bool param)12851debfc3dSmrg void set_pass_param (unsigned int n, bool param)
12861debfc3dSmrg {
12871debfc3dSmrg gcc_assert (n == 0);
12881debfc3dSmrg insert_min_max_p = param;
12891debfc3dSmrg }
12901debfc3dSmrg virtual unsigned int execute (function *);
12911debfc3dSmrg
12921debfc3dSmrg private:
12931debfc3dSmrg /* Determines whether the pass instance creates MIN/MAX_EXPRs. */
12941debfc3dSmrg bool insert_min_max_p;
12951debfc3dSmrg }; // class pass_object_sizes
12961debfc3dSmrg
12971debfc3dSmrg /* Dummy valueize function. */
12981debfc3dSmrg
12991debfc3dSmrg static tree
do_valueize(tree t)13001debfc3dSmrg do_valueize (tree t)
13011debfc3dSmrg {
13021debfc3dSmrg return t;
13031debfc3dSmrg }
13041debfc3dSmrg
13051debfc3dSmrg unsigned int
execute(function * fun)13061debfc3dSmrg pass_object_sizes::execute (function *fun)
13071debfc3dSmrg {
13081debfc3dSmrg basic_block bb;
13091debfc3dSmrg FOR_EACH_BB_FN (bb, fun)
13101debfc3dSmrg {
13111debfc3dSmrg gimple_stmt_iterator i;
13121debfc3dSmrg for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
13131debfc3dSmrg {
13141debfc3dSmrg tree result;
13151debfc3dSmrg gimple *call = gsi_stmt (i);
13161debfc3dSmrg if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE))
13171debfc3dSmrg continue;
13181debfc3dSmrg
13191debfc3dSmrg init_object_sizes ();
13201debfc3dSmrg
13211debfc3dSmrg /* If insert_min_max_p, only attempt to fold
13221debfc3dSmrg __builtin_object_size (x, 1) and __builtin_object_size (x, 3),
13231debfc3dSmrg and rather than folding the builtin to the constant if any,
13241debfc3dSmrg create a MIN_EXPR or MAX_EXPR of the __builtin_object_size
13251debfc3dSmrg call result and the computed constant. */
13261debfc3dSmrg if (insert_min_max_p)
13271debfc3dSmrg {
13281debfc3dSmrg tree ost = gimple_call_arg (call, 1);
13291debfc3dSmrg if (tree_fits_uhwi_p (ost))
13301debfc3dSmrg {
13311debfc3dSmrg unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost);
13321debfc3dSmrg tree ptr = gimple_call_arg (call, 0);
13331debfc3dSmrg tree lhs = gimple_call_lhs (call);
13341debfc3dSmrg if ((object_size_type == 1 || object_size_type == 3)
13351debfc3dSmrg && (TREE_CODE (ptr) == ADDR_EXPR
13361debfc3dSmrg || TREE_CODE (ptr) == SSA_NAME)
13371debfc3dSmrg && lhs)
13381debfc3dSmrg {
13391debfc3dSmrg tree type = TREE_TYPE (lhs);
13401debfc3dSmrg unsigned HOST_WIDE_INT bytes;
13411debfc3dSmrg if (compute_builtin_object_size (ptr, object_size_type,
13421debfc3dSmrg &bytes)
13431debfc3dSmrg && wi::fits_to_tree_p (bytes, type))
13441debfc3dSmrg {
13451debfc3dSmrg tree tem = make_ssa_name (type);
13461debfc3dSmrg gimple_call_set_lhs (call, tem);
13471debfc3dSmrg enum tree_code code
13481debfc3dSmrg = object_size_type == 1 ? MIN_EXPR : MAX_EXPR;
13491debfc3dSmrg tree cst = build_int_cstu (type, bytes);
13501debfc3dSmrg gimple *g
13511debfc3dSmrg = gimple_build_assign (lhs, code, tem, cst);
13521debfc3dSmrg gsi_insert_after (&i, g, GSI_NEW_STMT);
13531debfc3dSmrg update_stmt (call);
13541debfc3dSmrg }
13551debfc3dSmrg }
13561debfc3dSmrg }
13571debfc3dSmrg continue;
13581debfc3dSmrg }
13591debfc3dSmrg
13601debfc3dSmrg tree lhs = gimple_call_lhs (call);
13611debfc3dSmrg if (!lhs)
13621debfc3dSmrg continue;
13631debfc3dSmrg
13641debfc3dSmrg result = gimple_fold_stmt_to_constant (call, do_valueize);
13651debfc3dSmrg if (!result)
13661debfc3dSmrg {
13671debfc3dSmrg tree ost = gimple_call_arg (call, 1);
13681debfc3dSmrg
13691debfc3dSmrg if (tree_fits_uhwi_p (ost))
13701debfc3dSmrg {
13711debfc3dSmrg unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost);
13721debfc3dSmrg
13731debfc3dSmrg if (object_size_type < 2)
13741debfc3dSmrg result = fold_convert (size_type_node,
13751debfc3dSmrg integer_minus_one_node);
13761debfc3dSmrg else if (object_size_type < 4)
13771debfc3dSmrg result = build_zero_cst (size_type_node);
13781debfc3dSmrg }
13791debfc3dSmrg
13801debfc3dSmrg if (!result)
13811debfc3dSmrg continue;
13821debfc3dSmrg }
13831debfc3dSmrg
13841debfc3dSmrg gcc_assert (TREE_CODE (result) == INTEGER_CST);
13851debfc3dSmrg
13861debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
13871debfc3dSmrg {
13881debfc3dSmrg fprintf (dump_file, "Simplified\n ");
13891debfc3dSmrg print_gimple_stmt (dump_file, call, 0, dump_flags);
13901debfc3dSmrg fprintf (dump_file, " to ");
1391a2dc1f3fSmrg print_generic_expr (dump_file, result);
13921debfc3dSmrg fprintf (dump_file, "\n");
13931debfc3dSmrg }
13941debfc3dSmrg
13951debfc3dSmrg /* Propagate into all uses and fold those stmts. */
1396*8feb0f0bSmrg if (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
13971debfc3dSmrg replace_uses_by (lhs, result);
1398*8feb0f0bSmrg else
1399*8feb0f0bSmrg replace_call_with_value (&i, result);
14001debfc3dSmrg }
14011debfc3dSmrg }
14021debfc3dSmrg
14031debfc3dSmrg fini_object_sizes ();
14041debfc3dSmrg return 0;
14051debfc3dSmrg }
14061debfc3dSmrg
14071debfc3dSmrg } // anon namespace
14081debfc3dSmrg
14091debfc3dSmrg gimple_opt_pass *
make_pass_object_sizes(gcc::context * ctxt)14101debfc3dSmrg make_pass_object_sizes (gcc::context *ctxt)
14111debfc3dSmrg {
14121debfc3dSmrg return new pass_object_sizes (ctxt);
14131debfc3dSmrg }
1414