This patch adds a way of treating certain kinds of CONST as unique, so that pointer equality is equivalent to value equality. For now it is restricted to VEC_DUPLICATE and VEC_SERIES, although the code to generate them remains in the else arm of an "if (1)" until a later patch.
This is needed so that (const (vec_duplicate xx)) can used as the CONSTxx_RTX of a variable-length vector. 2017-10-23 Richard Sandiford <richard.sandif...@linaro.org> Alan Hayward <alan.hayw...@arm.com> David Sherwood <david.sherw...@arm.com> gcc/ * rtl.h (unique_const_p): New function. (gen_rtx_CONST): Declare. * emit-rtl.c (const_hasher): New struct. (const_htab): New variable. (init_emit_once): Initialize it. (const_hasher::hash, const_hasher::equal): New functions. (gen_rtx_CONST): New function. (spare_vec_duplicate, spare_vec_series): New variables. (gen_const_vec_duplicate_1): Add code for use (const (vec_duplicate)), but disable it for now. (gen_const_vec_series): Likewise (const (vec_series)). * gengenrtl.c (special_rtx): Return true for CONST. * rtl.c (shared_const_p): Return true if unique_const_p. Index: gcc/rtl.h =================================================================== --- gcc/rtl.h 2017-10-23 11:41:41.549050496 +0100 +++ gcc/rtl.h 2017-10-23 11:42:47.297720974 +0100 @@ -2861,6 +2861,23 @@ vec_series_p (const_rtx x, rtx *base_out return const_vec_series_p (x, base_out, step_out); } +/* Return true if there should only ever be one instance of (const X), + so that constants of this type can be compared using pointer equality. */ + +inline bool +unique_const_p (const_rtx x) +{ + switch (GET_CODE (x)) + { + case VEC_DUPLICATE: + case VEC_SERIES: + return true; + + default: + return false; + } +} + /* Return the unpromoted (outer) mode of SUBREG_PROMOTED_VAR_P subreg X. */ inline scalar_int_mode @@ -3542,6 +3559,7 @@ extern rtx_insn_list *gen_rtx_INSN_LIST gen_rtx_INSN (machine_mode mode, rtx_insn *prev_insn, rtx_insn *next_insn, basic_block bb, rtx pattern, int location, int code, rtx reg_notes); +extern rtx gen_rtx_CONST (machine_mode, rtx); extern rtx gen_rtx_CONST_INT (machine_mode, HOST_WIDE_INT); extern rtx gen_rtx_CONST_VECTOR (machine_mode, rtvec); extern void set_mode_and_regno (rtx, machine_mode, unsigned int); Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c 2017-10-23 11:41:41.548050496 +0100 +++ gcc/emit-rtl.c 2017-10-23 11:42:47.296720974 +0100 @@ -175,6 +175,15 @@ struct const_fixed_hasher : ggc_cache_pt static GTY ((cache)) hash_table<const_fixed_hasher> *const_fixed_htab; +/* A hash table storing unique CONSTs. */ +struct const_hasher : ggc_cache_ptr_hash<rtx_def> +{ + static hashval_t hash (rtx x); + static bool equal (rtx x, rtx y); +}; + +static GTY ((cache)) hash_table<const_hasher> *const_htab; + #define cur_insn_uid (crtl->emit.x_cur_insn_uid) #define cur_debug_insn_uid (crtl->emit.x_cur_debug_insn_uid) #define first_label_num (crtl->emit.x_first_label_num) @@ -310,6 +319,28 @@ const_fixed_hasher::equal (rtx x, rtx y) return fixed_identical (CONST_FIXED_VALUE (a), CONST_FIXED_VALUE (b)); } +/* Returns a hash code for X (which is either an existing unique CONST + or an operand to gen_rtx_CONST). */ + +hashval_t +const_hasher::hash (rtx x) +{ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + + int do_not_record_p = 0; + return hash_rtx (x, GET_MODE (x), &do_not_record_p, NULL, false); +} + +/* Returns true if the operand of unique CONST X is equal to Y. */ + +bool +const_hasher::equal (rtx x, rtx y) +{ + gcc_checking_assert (GET_CODE (x) == CONST); + return rtx_equal_p (XEXP (x, 0), y); +} + /* Return true if the given memory attributes are equal. */ bool @@ -5756,16 +5787,55 @@ init_emit (void) #endif } +rtx +gen_rtx_CONST (machine_mode mode, rtx val) +{ + if (unique_const_p (val)) + { + /* Look up the CONST in the hash table. */ + rtx *slot = const_htab->find_slot (val, INSERT); + if (*slot == 0) + *slot = gen_rtx_raw_CONST (mode, val); + return *slot; + } + + return gen_rtx_raw_CONST (mode, val); +} + +/* Temporary rtx used by gen_const_vec_duplicate_1. */ +static GTY((deletable)) rtx spare_vec_duplicate; + /* Like gen_const_vec_duplicate, but ignore const_tiny_rtx. */ static rtx gen_const_vec_duplicate_1 (machine_mode mode, rtx el) { int nunits = GET_MODE_NUNITS (mode); - rtvec v = rtvec_alloc (nunits); - for (int i = 0; i < nunits; ++i) - RTVEC_ELT (v, i) = el; - return gen_rtx_raw_CONST_VECTOR (mode, v); + if (1) + { + rtvec v = rtvec_alloc (nunits); + + for (int i = 0; i < nunits; ++i) + RTVEC_ELT (v, i) = el; + + return gen_rtx_raw_CONST_VECTOR (mode, v); + } + else + { + if (spare_vec_duplicate) + { + PUT_MODE (spare_vec_duplicate, mode); + XEXP (spare_vec_duplicate, 0) = el; + } + else + spare_vec_duplicate = gen_rtx_VEC_DUPLICATE (mode, el); + + rtx res = gen_rtx_CONST (mode, spare_vec_duplicate); + if (XEXP (res, 0) == spare_vec_duplicate) + spare_vec_duplicate = NULL_RTX; + + return res; + } } /* Generate a vector constant of mode MODE in which every element has @@ -5827,6 +5897,9 @@ const_vec_series_p_1 (const_rtx x, rtx * return true; } +/* Temporary rtx used by gen_const_vec_series. */ +static GTY((deletable)) rtx spare_vec_series; + /* Generate a vector constant of mode MODE in which element I has the value BASE + I * STEP. */ @@ -5836,13 +5909,33 @@ gen_const_vec_series (machine_mode mode, gcc_assert (CONSTANT_P (base) && CONSTANT_P (step)); int nunits = GET_MODE_NUNITS (mode); - rtvec v = rtvec_alloc (nunits); - scalar_mode inner_mode = GET_MODE_INNER (mode); - RTVEC_ELT (v, 0) = base; - for (int i = 1; i < nunits; ++i) - RTVEC_ELT (v, i) = simplify_gen_binary (PLUS, inner_mode, - RTVEC_ELT (v, i - 1), step); - return gen_rtx_raw_CONST_VECTOR (mode, v); + if (1) + { + rtvec v = rtvec_alloc (nunits); + scalar_mode inner_mode = GET_MODE_INNER (mode); + RTVEC_ELT (v, 0) = base; + for (int i = 1; i < nunits; ++i) + RTVEC_ELT (v, i) = simplify_gen_binary (PLUS, inner_mode, + RTVEC_ELT (v, i - 1), step); + return gen_rtx_raw_CONST_VECTOR (mode, v); + } + else + { + if (spare_vec_series) + { + PUT_MODE (spare_vec_series, mode); + XEXP (spare_vec_series, 0) = base; + XEXP (spare_vec_series, 1) = step; + } + else + spare_vec_series = gen_rtx_VEC_SERIES (mode, base, step); + + rtx res = gen_rtx_CONST (mode, spare_vec_series); + if (XEXP (res, 0) == spare_vec_series) + spare_vec_series = NULL_RTX; + + return res; + } } /* Generate a vector of mode MODE in which element I has the value @@ -6000,6 +6093,8 @@ init_emit_once (void) reg_attrs_htab = hash_table<reg_attr_hasher>::create_ggc (37); + const_htab = hash_table<const_hasher>::create_ggc (37); + #ifdef INIT_EXPANDERS /* This is to initialize {init|mark|free}_machine_status before the first call to push_function_context_to. This is needed by the Chill front Index: gcc/gengenrtl.c =================================================================== --- gcc/gengenrtl.c 2017-08-03 10:40:53.029491180 +0100 +++ gcc/gengenrtl.c 2017-10-23 11:42:47.297720974 +0100 @@ -143,7 +143,8 @@ special_rtx (int idx) || strcmp (defs[idx].enumname, "CC0") == 0 || strcmp (defs[idx].enumname, "RETURN") == 0 || strcmp (defs[idx].enumname, "SIMPLE_RETURN") == 0 - || strcmp (defs[idx].enumname, "CONST_VECTOR") == 0); + || strcmp (defs[idx].enumname, "CONST_VECTOR") == 0 + || strcmp (defs[idx].enumname, "CONST") == 0); } /* Return nonzero if the RTL code given by index IDX is one that we should Index: gcc/rtl.c =================================================================== --- gcc/rtl.c 2017-08-03 10:40:55.646123304 +0100 +++ gcc/rtl.c 2017-10-23 11:42:47.297720974 +0100 @@ -252,6 +252,9 @@ shared_const_p (const_rtx orig) { gcc_assert (GET_CODE (orig) == CONST); + if (unique_const_p (XEXP (orig, 0))) + return true; + /* CONST can be shared if it contains a SYMBOL_REF. If it contains a LABEL_REF, it isn't sharable. */ return (GET_CODE (XEXP (orig, 0)) == PLUS