diff options
author | Richard Sandiford <richard.sandiford@linaro.org> | 2017-12-20 12:51:50 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2017-12-20 12:51:50 +0000 |
commit | 36fd64086542ed734aded849304723218fa4d6fd (patch) | |
tree | 8ecb64d56e437c9912d8f6db4a70c9aec93c5019 /gcc/tree.h | |
parent | 0c12fc9b2d605cf323cfdab28a972d86398e71a1 (diff) |
poly_int: tree constants
This patch adds a tree representation for poly_ints. Unlike the
rtx version, the coefficients are INTEGER_CSTs rather than plain
integers, so that we can easily access them as poly_widest_ints
and poly_offset_ints.
The patch also adjusts some places that previously
relied on "constant" meaning "INTEGER_CST". It also makes
sure that the TYPE_SIZE agrees with the TYPE_SIZE_UNIT for
vector booleans, given the existing:
/* Several boolean vector elements may fit in a single unit. */
if (VECTOR_BOOLEAN_TYPE_P (type)
&& type->type_common.mode != BLKmode)
TYPE_SIZE_UNIT (type)
= size_int (GET_MODE_SIZE (type->type_common.mode));
else
TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR,
TYPE_SIZE_UNIT (innertype),
size_int (nunits));
2017-12-20 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
gcc/
* doc/generic.texi (POLY_INT_CST): Document.
* tree.def (POLY_INT_CST): New tree code.
* treestruct.def (TS_POLY_INT_CST): New tree layout.
* tree-core.h (tree_poly_int_cst): New struct.
(tree_node): Add a poly_int_cst field.
* tree.h (POLY_INT_CST_P, POLY_INT_CST_COEFF): New macros.
(wide_int_to_tree, force_fit_type): Take a poly_wide_int_ref
instead of a wide_int_ref.
(build_int_cst, build_int_cst_type): Take a poly_int64 instead
of a HOST_WIDE_INT.
(build_int_cstu, build_array_type_nelts): Take a poly_uint64
instead of an unsigned HOST_WIDE_INT.
(build_poly_int_cst, tree_fits_poly_int64_p, tree_fits_poly_uint64_p)
(ptrdiff_tree_p): Declare.
(tree_to_poly_int64, tree_to_poly_uint64): Likewise. Provide
extern inline implementations if the target doesn't use POLY_INT_CST.
(poly_int_tree_p): New function.
(wi::unextended_tree): New class.
(wi::int_traits <unextended_tree>): New override.
(wi::extended_tree): Add a default constructor.
(wi::extended_tree::get_tree): New function.
(wi::widest_extended_tree, wi::offset_extended_tree): New typedefs.
(wi::tree_to_widest_ref, wi::tree_to_offset_ref): Use them.
(wi::tree_to_poly_widest_ref, wi::tree_to_poly_offset_ref)
(wi::tree_to_poly_wide_ref): New typedefs.
(wi::ints_for): Provide overloads for extended_tree and
unextended_tree.
(poly_int_cst_value, wi::to_poly_widest, wi::to_poly_offset)
(wi::to_wide): New functions.
(wi::fits_to_boolean_p, wi::fits_to_tree_p): Handle poly_ints.
* tree.c (poly_int_cst_hasher): New struct.
(poly_int_cst_hash_table): New variable.
(tree_node_structure_for_code, tree_code_size, simple_cst_equal)
(valid_constant_size_p, add_expr, drop_tree_overflow): Handle
POLY_INT_CST.
(initialize_tree_contains_struct): Handle TS_POLY_INT_CST.
(init_ttree): Initialize poly_int_cst_hash_table.
(build_int_cst, build_int_cst_type, build_invariant_address): Take
a poly_int64 instead of a HOST_WIDE_INT.
(build_int_cstu, build_array_type_nelts): Take a poly_uint64
instead of an unsigned HOST_WIDE_INT.
(wide_int_to_tree): Rename to...
(wide_int_to_tree_1): ...this.
(build_new_poly_int_cst, build_poly_int_cst): New functions.
(force_fit_type): Take a poly_wide_int_ref instead of a wide_int_ref.
(wide_int_to_tree): New function that takes a poly_wide_int_ref.
(ptrdiff_tree_p, tree_to_poly_int64, tree_to_poly_uint64)
(tree_fits_poly_int64_p, tree_fits_poly_uint64_p): New functions.
* lto-streamer-out.c (DFS::DFS_write_tree_body, hash_tree): Handle
TS_POLY_INT_CST.
* tree-streamer-in.c (lto_input_ts_poly_tree_pointers): Likewise.
(streamer_read_tree_body): Likewise.
* tree-streamer-out.c (write_ts_poly_tree_pointers): Likewise.
(streamer_write_tree_body): Likewise.
* tree-streamer.c (streamer_check_handled_ts_structures): Likewise.
* asan.c (asan_protect_global): Require the size to be an INTEGER_CST.
* cfgexpand.c (expand_debug_expr): Handle POLY_INT_CST.
* expr.c (expand_expr_real_1, const_vector_from_tree): Likewise.
* gimple-expr.h (is_gimple_constant): Likewise.
* gimplify.c (maybe_with_size_expr): Likewise.
* print-tree.c (print_node): Likewise.
* tree-data-ref.c (data_ref_compare_tree): Likewise.
* tree-pretty-print.c (dump_generic_node): Likewise.
* tree-ssa-address.c (addr_for_mem_ref): Likewise.
* tree-vect-data-refs.c (dr_group_sort_cmp): Likewise.
* tree-vrp.c (compare_values_warnv): Likewise.
* tree-ssa-loop-ivopts.c (determine_base_object, constant_multiple_of)
(get_loop_invariant_expr, add_candidate_1, get_computation_aff_1)
(force_expr_to_var_cost): Likewise.
* tree-ssa-loop.c (for_each_index): Likewise.
* fold-const.h (build_invariant_address, size_int_kind): Take a
poly_int64 instead of a HOST_WIDE_INT.
* fold-const.c (fold_negate_expr_1, const_binop, const_unop)
(fold_convert_const, multiple_of_p, fold_negate_const): Handle
POLY_INT_CST.
(size_binop_loc): Likewise. Allow int_const_binop_1 to fail.
(int_const_binop_2): New function, split out from...
(int_const_binop_1): ...here. Handle POLY_INT_CST.
(size_int_kind): Take a poly_int64 instead of a HOST_WIDE_INT.
* expmed.c (make_tree): Handle CONST_POLY_INT_P.
* gimple-ssa-strength-reduction.c (slsr_process_add)
(slsr_process_mul): Check for INTEGER_CSTs before using them
as candidates.
* stor-layout.c (bits_from_bytes): New function.
(bit_from_pos): Use it.
(layout_type): Likewise. For vectors, multiply the TYPE_SIZE_UNIT
by BITS_PER_UNIT to get the TYPE_SIZE.
* tree-cfg.c (verify_expr, verify_types_in_gimple_reference): Allow
MEM_REF and TARGET_MEM_REF offsets to be a POLY_INT_CST.
Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r255863
Diffstat (limited to 'gcc/tree.h')
-rw-r--r-- | gcc/tree.h | 242 |
1 files changed, 225 insertions, 17 deletions
diff --git a/gcc/tree.h b/gcc/tree.h index ae40e903e4c..a7b8c2f400c 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -991,6 +991,15 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define TREE_INT_CST_LOW(NODE) \ ((unsigned HOST_WIDE_INT) TREE_INT_CST_ELT (NODE, 0)) +/* Return true if NODE is a POLY_INT_CST. This is only ever true on + targets with variable-sized modes. */ +#define POLY_INT_CST_P(NODE) \ + (NUM_POLY_INT_COEFFS > 1 && TREE_CODE (NODE) == POLY_INT_CST) + +/* In a POLY_INT_CST node. */ +#define POLY_INT_CST_COEFF(NODE, I) \ + (POLY_INT_CST_CHECK (NODE)->poly_int_cst.coeffs[I]) + #define TREE_REAL_CST_PTR(NODE) (REAL_CST_CHECK (NODE)->real_cst.real_cst_ptr) #define TREE_REAL_CST(NODE) (*TREE_REAL_CST_PTR (NODE)) @@ -4040,15 +4049,15 @@ build5_loc (location_t loc, enum tree_code code, tree type, tree arg0, extern tree double_int_to_tree (tree, double_int); -extern tree wide_int_to_tree (tree type, const wide_int_ref &cst); -extern tree force_fit_type (tree, const wide_int_ref &, int, bool); +extern tree wide_int_to_tree (tree type, const poly_wide_int_ref &cst); +extern tree force_fit_type (tree, const poly_wide_int_ref &, int, bool); /* Create an INT_CST node with a CST value zero extended. */ /* static inline */ -extern tree build_int_cst (tree, HOST_WIDE_INT); -extern tree build_int_cstu (tree type, unsigned HOST_WIDE_INT cst); -extern tree build_int_cst_type (tree, HOST_WIDE_INT); +extern tree build_int_cst (tree, poly_int64); +extern tree build_int_cstu (tree type, poly_uint64); +extern tree build_int_cst_type (tree, poly_int64); extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO); extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *); extern tree build_vector_from_val (tree, tree); @@ -4068,6 +4077,7 @@ extern tree build_minus_one_cst (tree); extern tree build_all_ones_cst (tree); extern tree build_zero_cst (tree); extern tree build_string (int, const char *); +extern tree build_poly_int_cst (tree, const poly_wide_int_ref &); extern tree build_tree_list (tree, tree CXX_MEM_STAT_INFO); extern tree build_tree_list_vec (const vec<tree, va_gc> * CXX_MEM_STAT_INFO); extern tree build_decl (location_t, enum tree_code, @@ -4117,7 +4127,7 @@ extern tree build_opaque_vector_type (tree innertype, int nunits); extern tree build_index_type (tree); extern tree build_array_type (tree, tree, bool = false); extern tree build_nonshared_array_type (tree, tree); -extern tree build_array_type_nelts (tree, unsigned HOST_WIDE_INT); +extern tree build_array_type_nelts (tree, poly_uint64); extern tree build_function_type (tree, tree); extern tree build_function_type_list (tree, ...); extern tree build_varargs_function_type_list (tree, ...); @@ -4141,12 +4151,14 @@ extern tree chain_index (int, tree); extern int tree_int_cst_equal (const_tree, const_tree); -extern bool tree_fits_shwi_p (const_tree) - ATTRIBUTE_PURE; -extern bool tree_fits_uhwi_p (const_tree) - ATTRIBUTE_PURE; +extern bool tree_fits_shwi_p (const_tree) ATTRIBUTE_PURE; +extern bool tree_fits_poly_int64_p (const_tree) ATTRIBUTE_PURE; +extern bool tree_fits_uhwi_p (const_tree) ATTRIBUTE_PURE; +extern bool tree_fits_poly_uint64_p (const_tree) ATTRIBUTE_PURE; extern HOST_WIDE_INT tree_to_shwi (const_tree); +extern poly_int64 tree_to_poly_int64 (const_tree); extern unsigned HOST_WIDE_INT tree_to_uhwi (const_tree); +extern poly_uint64 tree_to_poly_uint64 (const_tree); #if !defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 4003) extern inline __attribute__ ((__gnu_inline__)) HOST_WIDE_INT tree_to_shwi (const_tree t) @@ -4161,6 +4173,21 @@ tree_to_uhwi (const_tree t) gcc_assert (tree_fits_uhwi_p (t)); return TREE_INT_CST_LOW (t); } +#if NUM_POLY_INT_COEFFS == 1 +extern inline __attribute__ ((__gnu_inline__)) poly_int64 +tree_to_poly_int64 (const_tree t) +{ + gcc_assert (tree_fits_poly_int64_p (t)); + return TREE_INT_CST_LOW (t); +} + +extern inline __attribute__ ((__gnu_inline__)) poly_uint64 +tree_to_poly_uint64 (const_tree t) +{ + gcc_assert (tree_fits_poly_uint64_p (t)); + return TREE_INT_CST_LOW (t); +} +#endif #endif extern int tree_int_cst_sgn (const_tree); extern int tree_int_cst_sign_bit (const_tree); @@ -4169,6 +4196,33 @@ extern tree strip_array_types (tree); extern tree excess_precision_type (tree); extern bool valid_constant_size_p (const_tree); +/* Return true if T holds a value that can be represented as a poly_int64 + without loss of precision. Store the value in *VALUE if so. */ + +inline bool +poly_int_tree_p (const_tree t, poly_int64_pod *value) +{ + if (tree_fits_poly_int64_p (t)) + { + *value = tree_to_poly_int64 (t); + return true; + } + return false; +} + +/* Return true if T holds a value that can be represented as a poly_uint64 + without loss of precision. Store the value in *VALUE if so. */ + +inline bool +poly_int_tree_p (const_tree t, poly_uint64_pod *value) +{ + if (tree_fits_poly_uint64_p (t)) + { + *value = tree_to_poly_uint64 (t); + return true; + } + return false; +} /* From expmed.c. Since rtl.h is included after tree.h, we can't put the prototype here. Rtl.h does declare the prototype if @@ -4722,8 +4776,17 @@ complete_or_array_type_p (const_tree type) && COMPLETE_TYPE_P (TREE_TYPE (type))); } +/* Return true if the value of T could be represented as a poly_widest_int. */ + +inline bool +poly_int_tree_p (const_tree t) +{ + return (TREE_CODE (t) == INTEGER_CST || POLY_INT_CST_P (t)); +} + extern tree strip_float_extensions (tree); extern int really_constant_p (const_tree); +extern bool ptrdiff_tree_p (const_tree, poly_int64_pod *); extern bool decl_address_invariant_p (const_tree); extern bool decl_address_ip_invariant_p (const_tree); extern bool int_fits_type_p (const_tree, const_tree); @@ -5159,6 +5222,29 @@ extern bool anon_aggrname_p (const_tree); /* The tree and const_tree overload templates. */ namespace wi { + class unextended_tree + { + private: + const_tree m_t; + + public: + unextended_tree () {} + unextended_tree (const_tree t) : m_t (t) {} + + unsigned int get_precision () const; + const HOST_WIDE_INT *get_val () const; + unsigned int get_len () const; + const_tree get_tree () const { return m_t; } + }; + + template <> + struct int_traits <unextended_tree> + { + static const enum precision_type precision_type = VAR_PRECISION; + static const bool host_dependent_precision = false; + static const bool is_sign_extended = false; + }; + template <int N> class extended_tree { @@ -5166,11 +5252,13 @@ namespace wi const_tree m_t; public: + extended_tree () {} extended_tree (const_tree); unsigned int get_precision () const; const HOST_WIDE_INT *get_val () const; unsigned int get_len () const; + const_tree get_tree () const { return m_t; } }; template <int N> @@ -5182,10 +5270,11 @@ namespace wi static const unsigned int precision = N; }; - typedef const generic_wide_int <extended_tree <WIDE_INT_MAX_PRECISION> > - tree_to_widest_ref; - typedef const generic_wide_int <extended_tree <ADDR_MAX_PRECISION> > - tree_to_offset_ref; + typedef extended_tree <WIDE_INT_MAX_PRECISION> widest_extended_tree; + typedef extended_tree <ADDR_MAX_PRECISION> offset_extended_tree; + + typedef const generic_wide_int <widest_extended_tree> tree_to_widest_ref; + typedef const generic_wide_int <offset_extended_tree> tree_to_offset_ref; typedef const generic_wide_int<wide_int_ref_storage<false, false> > tree_to_wide_ref; @@ -5193,6 +5282,34 @@ namespace wi tree_to_offset_ref to_offset (const_tree); tree_to_wide_ref to_wide (const_tree); wide_int to_wide (const_tree, unsigned int); + + typedef const poly_int <NUM_POLY_INT_COEFFS, + generic_wide_int <widest_extended_tree> > + tree_to_poly_widest_ref; + typedef const poly_int <NUM_POLY_INT_COEFFS, + generic_wide_int <offset_extended_tree> > + tree_to_poly_offset_ref; + typedef const poly_int <NUM_POLY_INT_COEFFS, + generic_wide_int <unextended_tree> > + tree_to_poly_wide_ref; + + tree_to_poly_widest_ref to_poly_widest (const_tree); + tree_to_poly_offset_ref to_poly_offset (const_tree); + tree_to_poly_wide_ref to_poly_wide (const_tree); + + template <int N> + struct ints_for <generic_wide_int <extended_tree <N> >, CONST_PRECISION> + { + typedef generic_wide_int <extended_tree <N> > extended; + static extended zero (const extended &); + }; + + template <> + struct ints_for <generic_wide_int <unextended_tree>, VAR_PRECISION> + { + typedef generic_wide_int <unextended_tree> unextended; + static unextended zero (const unextended &); + }; } /* Refer to INTEGER_CST T as though it were a widest_int. @@ -5337,6 +5454,95 @@ wi::extended_tree <N>::get_len () const gcc_unreachable (); } +inline unsigned int +wi::unextended_tree::get_precision () const +{ + return TYPE_PRECISION (TREE_TYPE (m_t)); +} + +inline const HOST_WIDE_INT * +wi::unextended_tree::get_val () const +{ + return &TREE_INT_CST_ELT (m_t, 0); +} + +inline unsigned int +wi::unextended_tree::get_len () const +{ + return TREE_INT_CST_NUNITS (m_t); +} + +/* Return the value of a POLY_INT_CST in its native precision. */ + +inline wi::tree_to_poly_wide_ref +poly_int_cst_value (const_tree x) +{ + poly_int <NUM_POLY_INT_COEFFS, generic_wide_int <wi::unextended_tree> > res; + for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i) + res.coeffs[i] = POLY_INT_CST_COEFF (x, i); + return res; +} + +/* Access INTEGER_CST or POLY_INT_CST tree T as if it were a + poly_widest_int. See wi::to_widest for more details. */ + +inline wi::tree_to_poly_widest_ref +wi::to_poly_widest (const_tree t) +{ + if (POLY_INT_CST_P (t)) + { + poly_int <NUM_POLY_INT_COEFFS, + generic_wide_int <widest_extended_tree> > res; + for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i) + res.coeffs[i] = POLY_INT_CST_COEFF (t, i); + return res; + } + return t; +} + +/* Access INTEGER_CST or POLY_INT_CST tree T as if it were a + poly_offset_int. See wi::to_offset for more details. */ + +inline wi::tree_to_poly_offset_ref +wi::to_poly_offset (const_tree t) +{ + if (POLY_INT_CST_P (t)) + { + poly_int <NUM_POLY_INT_COEFFS, + generic_wide_int <offset_extended_tree> > res; + for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i) + res.coeffs[i] = POLY_INT_CST_COEFF (t, i); + return res; + } + return t; +} + +/* Access INTEGER_CST or POLY_INT_CST tree T as if it were a + poly_wide_int. See wi::to_wide for more details. */ + +inline wi::tree_to_poly_wide_ref +wi::to_poly_wide (const_tree t) +{ + if (POLY_INT_CST_P (t)) + return poly_int_cst_value (t); + return t; +} + +template <int N> +inline generic_wide_int <wi::extended_tree <N> > +wi::ints_for <generic_wide_int <wi::extended_tree <N> >, + wi::CONST_PRECISION>::zero (const extended &x) +{ + return build_zero_cst (TREE_TYPE (x.get_tree ())); +} + +inline generic_wide_int <wi::unextended_tree> +wi::ints_for <generic_wide_int <wi::unextended_tree>, + wi::VAR_PRECISION>::zero (const unextended &x) +{ + return build_zero_cst (TREE_TYPE (x.get_tree ())); +} + namespace wi { template <typename T> @@ -5354,7 +5560,9 @@ template <typename T> bool wi::fits_to_boolean_p (const T &x, const_tree type) { - return eq_p (x, 0) || eq_p (x, TYPE_UNSIGNED (type) ? 1 : -1); + typedef typename poly_int_traits<T>::int_type int_type; + return (known_eq (x, int_type (0)) + || known_eq (x, int_type (TYPE_UNSIGNED (type) ? 1 : -1))); } template <typename T> @@ -5367,9 +5575,9 @@ wi::fits_to_tree_p (const T &x, const_tree type) return fits_to_boolean_p (x, type); if (TYPE_UNSIGNED (type)) - return eq_p (x, zext (x, TYPE_PRECISION (type))); + return known_eq (x, zext (x, TYPE_PRECISION (type))); else - return eq_p (x, sext (x, TYPE_PRECISION (type))); + return known_eq (x, sext (x, TYPE_PRECISION (type))); } /* Produce the smallest number that is represented in TYPE. The precision |