aboutsummaryrefslogtreecommitdiff
path: root/gcc/rtl.h
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@linaro.org>2017-12-20 12:51:36 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2017-12-20 12:51:36 +0000
commit0c12fc9b2d605cf323cfdab28a972d86398e71a1 (patch)
treeca58581589b8fa244d77652a9a9c06f5293a8bea /gcc/rtl.h
parentabd3c800109b95f09af3b3f1a7a43d9b7631f21c (diff)
downloadgcc-0c12fc9b2d605cf323cfdab28a972d86398e71a1.zip
gcc-0c12fc9b2d605cf323cfdab28a972d86398e71a1.tar.gz
gcc-0c12fc9b2d605cf323cfdab28a972d86398e71a1.tar.bz2
poly_int: rtx constants
This patch adds an rtl representation of poly_int values. There were three possible ways of doing this: (1) Add a new rtl code for the poly_ints themselves and store the coefficients as trailing wide_ints. This would give constants like: (const_poly_int [c0 c1 ... cn]) The runtime value would be: c0 + c1 * x1 + ... + cn * xn (2) Like (1), but use rtxes for the coefficients. This would give constants like: (const_poly_int [(const_int c0) (const_int c1) ... (const_int cn)]) although the coefficients could be const_wide_ints instead of const_ints where appropriate. (3) Add a new rtl code for the polynomial indeterminates, then use them in const wrappers. A constant like c0 + c1 * x1 would then look like: (const:M (plus:M (mult:M (const_param:M x1) (const_int c1)) (const_int c0))) There didn't seem to be that much to choose between them. The main advantage of (1) is that it's a more efficient representation and that we can refer to the cofficients directly as wide_int_storage. 2017-12-20 Richard Sandiford <richard.sandiford@linaro.org> Alan Hayward <alan.hayward@arm.com> David Sherwood <david.sherwood@arm.com> gcc/ * doc/rtl.texi (const_poly_int): Document. Also document the rtl sharing behavior. * gengenrtl.c (excluded_rtx): Return true for CONST_POLY_INT. * rtl.h (const_poly_int_def): New struct. (rtx_def::u): Add a cpi field. (CASE_CONST_UNIQUE, CASE_CONST_ANY): Add CONST_POLY_INT. (CONST_POLY_INT_P, CONST_POLY_INT_COEFFS): New macros. (wi::rtx_to_poly_wide_ref): New typedef (const_poly_int_value, wi::to_poly_wide, rtx_to_poly_int64) (poly_int_rtx_p): New functions. (trunc_int_for_mode): Declare a poly_int64 version. (plus_constant): Take a poly_int64 instead of a HOST_WIDE_INT. (immed_wide_int_const): Take a poly_wide_int_ref rather than a wide_int_ref. (strip_offset): Declare. (strip_offset_and_add): New function. * rtl.def (CONST_POLY_INT): New rtx code. * rtl.c (rtx_size): Handle CONST_POLY_INT. (shared_const_p): Use poly_int_rtx_p. * emit-rtl.h (gen_int_mode): Take a poly_int64 instead of a HOST_WIDE_INT. (gen_int_shift_amount): Likewise. * emit-rtl.c (const_poly_int_hasher): New class. (const_poly_int_htab): New variable. (init_emit_once): Initialize it when NUM_POLY_INT_COEFFS > 1. (const_poly_int_hasher::hash): New function. (const_poly_int_hasher::equal): Likewise. (gen_int_mode): Take a poly_int64 instead of a HOST_WIDE_INT. (immed_wide_int_const): Rename to... (immed_wide_int_const_1): ...this and make static. (immed_wide_int_const): New function, taking a poly_wide_int_ref instead of a wide_int_ref. (gen_int_shift_amount): Take a poly_int64 instead of a HOST_WIDE_INT. (gen_lowpart_common): Handle CONST_POLY_INT. * cse.c (hash_rtx_cb, equiv_constant): Likewise. * cselib.c (cselib_hash_rtx): Likewise. * dwarf2out.c (const_ok_for_output_1): Likewise. * expr.c (convert_modes): Likewise. * print-rtl.c (rtx_writer::print_rtx, print_value): Likewise. * rtlhash.c (add_rtx): Likewise. * explow.c (trunc_int_for_mode): Add a poly_int64 version. (plus_constant): Take a poly_int64 instead of a HOST_WIDE_INT. Handle existing CONST_POLY_INT rtxes. * expmed.h (expand_shift): Take a poly_int64 instead of a HOST_WIDE_INT. * expmed.c (expand_shift): Likewise. * rtlanal.c (strip_offset): New function. (commutative_operand_precedence): Give CONST_POLY_INT the same precedence as CONST_DOUBLE and put CONST_WIDE_INT between that and CONST_INT. * rtl-tests.c (const_poly_int_tests): New struct. (rtl_tests_c_tests): Use it. * simplify-rtx.c (simplify_const_unary_operation): Handle CONST_POLY_INT. (simplify_const_binary_operation): Likewise. (simplify_binary_operation_1): Fold additions of symbolic constants and CONST_POLY_INTs. (simplify_subreg): Handle extensions and truncations of CONST_POLY_INTs. (simplify_const_poly_int_tests): New struct. (simplify_rtx_c_tests): Use it. * wide-int.h (storage_ref): Add default constructor. (wide_int_ref_storage): Likewise. (trailing_wide_ints): Use GTY((user)). (trailing_wide_ints::operator[]): Add a const version. (trailing_wide_ints::get_precision): New function. (trailing_wide_ints::extra_size): Likewise. Co-Authored-By: Alan Hayward <alan.hayward@arm.com> Co-Authored-By: David Sherwood <david.sherwood@arm.com> From-SVN: r255862
Diffstat (limited to 'gcc/rtl.h')
-rw-r--r--gcc/rtl.h119
1 files changed, 115 insertions, 4 deletions
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3ef687e..7b2560d 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -280,6 +280,10 @@ struct GTY((variable_size)) hwivec_def {
#define CWI_PUT_NUM_ELEM(RTX, NUM) \
(RTL_FLAG_CHECK1("CWI_PUT_NUM_ELEM", (RTX), CONST_WIDE_INT)->u2.num_elem = (NUM))
+struct GTY((variable_size)) const_poly_int_def {
+ trailing_wide_ints<NUM_POLY_INT_COEFFS> coeffs;
+};
+
/* RTL expression ("rtx"). */
/* The GTY "desc" and "tag" options below are a kludge: we need a desc
@@ -424,6 +428,7 @@ struct GTY((desc("0"), tag("0"),
struct real_value rv;
struct fixed_value fv;
struct hwivec_def hwiv;
+ struct const_poly_int_def cpi;
} GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
};
@@ -734,6 +739,7 @@ struct GTY(()) rtvec_def {
#define CASE_CONST_UNIQUE \
case CONST_INT: \
case CONST_WIDE_INT: \
+ case CONST_POLY_INT: \
case CONST_DOUBLE: \
case CONST_FIXED
@@ -741,6 +747,7 @@ struct GTY(()) rtvec_def {
#define CASE_CONST_ANY \
case CONST_INT: \
case CONST_WIDE_INT: \
+ case CONST_POLY_INT: \
case CONST_DOUBLE: \
case CONST_FIXED: \
case CONST_VECTOR
@@ -773,6 +780,11 @@ struct GTY(()) rtvec_def {
/* Predicate yielding nonzero iff X is an rtx for a constant integer. */
#define CONST_WIDE_INT_P(X) (GET_CODE (X) == CONST_WIDE_INT)
+/* Predicate yielding nonzero iff X is an rtx for a polynomial constant
+ integer. */
+#define CONST_POLY_INT_P(X) \
+ (NUM_POLY_INT_COEFFS > 1 && GET_CODE (X) == CONST_POLY_INT)
+
/* Predicate yielding nonzero iff X is an rtx for a constant fixed-point. */
#define CONST_FIXED_P(X) (GET_CODE (X) == CONST_FIXED)
@@ -1914,6 +1926,12 @@ set_regno_raw (rtx x, unsigned int regno, unsigned int nregs)
#define CONST_WIDE_INT_NUNITS(RTX) CWI_GET_NUM_ELEM (RTX)
#define CONST_WIDE_INT_ELT(RTX, N) CWI_ELT (RTX, N)
+/* For a CONST_POLY_INT, CONST_POLY_INT_COEFFS gives access to the
+ individual coefficients, in the form of a trailing_wide_ints structure. */
+#define CONST_POLY_INT_COEFFS(RTX) \
+ (RTL_FLAG_CHECK1("CONST_POLY_INT_COEFFS", (RTX), \
+ CONST_POLY_INT)->u.cpi.coeffs)
+
/* For a CONST_DOUBLE:
#if TARGET_SUPPORTS_WIDE_INT == 0
For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
@@ -2227,6 +2245,84 @@ wi::max_value (machine_mode mode, signop sgn)
return max_value (GET_MODE_PRECISION (as_a <scalar_mode> (mode)), sgn);
}
+namespace wi
+{
+ typedef poly_int<NUM_POLY_INT_COEFFS,
+ generic_wide_int <wide_int_ref_storage <false, false> > >
+ rtx_to_poly_wide_ref;
+ rtx_to_poly_wide_ref to_poly_wide (const_rtx, machine_mode);
+}
+
+/* Return the value of a CONST_POLY_INT in its native precision. */
+
+inline wi::rtx_to_poly_wide_ref
+const_poly_int_value (const_rtx x)
+{
+ poly_int<NUM_POLY_INT_COEFFS, WIDE_INT_REF_FOR (wide_int)> res;
+ for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+ res.coeffs[i] = CONST_POLY_INT_COEFFS (x)[i];
+ return res;
+}
+
+/* Return true if X is a scalar integer or a CONST_POLY_INT. The value
+ can then be extracted using wi::to_poly_wide. */
+
+inline bool
+poly_int_rtx_p (const_rtx x)
+{
+ return CONST_SCALAR_INT_P (x) || CONST_POLY_INT_P (x);
+}
+
+/* Access X (which satisfies poly_int_rtx_p) as a poly_wide_int.
+ MODE is the mode of X. */
+
+inline wi::rtx_to_poly_wide_ref
+wi::to_poly_wide (const_rtx x, machine_mode mode)
+{
+ if (CONST_POLY_INT_P (x))
+ return const_poly_int_value (x);
+ return rtx_mode_t (const_cast<rtx> (x), mode);
+}
+
+/* Return the value of X as a poly_int64. */
+
+inline poly_int64
+rtx_to_poly_int64 (const_rtx x)
+{
+ if (CONST_POLY_INT_P (x))
+ {
+ poly_int64 res;
+ for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+ res.coeffs[i] = CONST_POLY_INT_COEFFS (x)[i].to_shwi ();
+ return res;
+ }
+ return INTVAL (x);
+}
+
+/* Return true if arbitrary value X is an integer constant that can
+ be represented as a poly_int64. Store the value in *RES if so,
+ otherwise leave it unmodified. */
+
+inline bool
+poly_int_rtx_p (const_rtx x, poly_int64_pod *res)
+{
+ if (CONST_INT_P (x))
+ {
+ *res = INTVAL (x);
+ return true;
+ }
+ if (CONST_POLY_INT_P (x))
+ {
+ for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+ if (!wi::fits_shwi_p (CONST_POLY_INT_COEFFS (x)[i]))
+ return false;
+ for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+ res->coeffs[i] = CONST_POLY_INT_COEFFS (x)[i].to_shwi ();
+ return true;
+ }
+ return false;
+}
+
extern void init_rtlanal (void);
extern int rtx_cost (rtx, machine_mode, enum rtx_code, int, bool);
extern int address_cost (rtx, machine_mode, addr_space_t, bool);
@@ -2764,7 +2860,8 @@ get_full_set_src_cost (rtx x, machine_mode mode, struct full_rtx_costs *c)
/* In explow.c */
extern HOST_WIDE_INT trunc_int_for_mode (HOST_WIDE_INT, machine_mode);
-extern rtx plus_constant (machine_mode, rtx, HOST_WIDE_INT, bool = false);
+extern poly_int64 trunc_int_for_mode (poly_int64, machine_mode);
+extern rtx plus_constant (machine_mode, rtx, poly_int64, bool = false);
extern HOST_WIDE_INT get_stack_check_protect (void);
/* In rtl.c */
@@ -3058,13 +3155,11 @@ extern void end_sequence (void);
extern double_int rtx_to_double_int (const_rtx);
#endif
extern void cwi_output_hex (FILE *, const_rtx);
-#ifndef GENERATOR_FILE
-extern rtx immed_wide_int_const (const wide_int_ref &, machine_mode);
-#endif
#if TARGET_SUPPORTS_WIDE_INT == 0
extern rtx immed_double_const (HOST_WIDE_INT, HOST_WIDE_INT,
machine_mode);
#endif
+extern rtx immed_wide_int_const (const poly_wide_int_ref &, machine_mode);
/* In varasm.c */
extern rtx force_const_mem (machine_mode, rtx);
@@ -3252,6 +3347,7 @@ extern HOST_WIDE_INT get_integer_term (const_rtx);
extern rtx get_related_value (const_rtx);
extern bool offset_within_block_p (const_rtx, HOST_WIDE_INT);
extern void split_const (rtx, rtx *, rtx *);
+extern rtx strip_offset (rtx, poly_int64_pod *);
extern bool unsigned_reg_p (rtx);
extern int reg_mentioned_p (const_rtx, const_rtx);
extern int count_occurrences (const_rtx, const_rtx, int);
@@ -4185,6 +4281,21 @@ load_extend_op (machine_mode mode)
return UNKNOWN;
}
+/* If X is a PLUS of a base and a constant offset, add the constant to *OFFSET
+ and return the base. Return X otherwise. */
+
+inline rtx
+strip_offset_and_add (rtx x, poly_int64_pod *offset)
+{
+ if (GET_CODE (x) == PLUS)
+ {
+ poly_int64 suboffset;
+ x = strip_offset (x, &suboffset);
+ *offset += suboffset;
+ }
+ return x;
+}
+
/* gtype-desc.c. */
extern void gt_ggc_mx (rtx &);
extern void gt_pch_nx (rtx &);