Richi has asked the we break the wide-int patch so that the individual port
and front end maintainers can review their parts without have to go through
the entire patch. This patch covers the first half of the rtl code.
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -2336,15 +2336,23 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
+ (unsigned int) INTVAL (x));
return hash;
+ case CONST_WIDE_INT:
+ {
+ int i;
+ for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+ hash += CONST_WIDE_INT_ELT (x, i);
+ }
+ return hash;
You can write "for (int i = 0; ..." now and remove the parentheses.
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -1121,15 +1120,23 @@ cselib_hash_rtx (rtx x, int create, enum machine_mode
memmode)
hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
return hash ? hash : (unsigned int) CONST_INT;
+ case CONST_WIDE_INT:
+ {
+ int i;
+ for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+ hash += CONST_WIDE_INT_ELT (x, i);
+ }
+ return hash;
+
Likewise.
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -3298,23 +3268,13 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n,
int precision,
pow = n + lgup;
pow2 = n + lgup - precision;
- /* We could handle this with some effort, but this case is much
- better handled directly with a scc insn, so rely on caller using
- that. */
- gcc_assert (pow != HOST_BITS_PER_DOUBLE_INT);
Why removing it?
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -722,64 +722,33 @@ convert_modes (enum machine_mode mode, enum machine_mode
oldmode, rtx x, int uns
if (mode == oldmode)
return x;
- /* There is one case that we must handle specially: If we are converting
- a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
- we are to interpret the constant as unsigned, gen_lowpart will do
- the wrong if the constant appears negative. What we want to do is
- make the high-order word of the constant zero, not all ones. */
-
- if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
- && CONST_INT_P (x) && INTVAL (x) < 0)
+ if (CONST_SCALAR_INT_P (x)
+ && GET_MODE_CLASS (mode) == MODE_INT)
On a single line.
{
- double_int val = double_int::from_uhwi (INTVAL (x));
-
- /* We need to zero extend VAL. */
- if (oldmode != VOIDmode)
- val = val.zext (GET_MODE_BITSIZE (oldmode));
-
- return immed_double_int_const (val, mode);
+ /* If the caller did not tell us the old mode, then there is
+ not much to do with respect to canonization. We have to assume
+ that all the bits are significant. */
+ if (GET_MODE_CLASS (oldmode) != MODE_INT)
+ oldmode = MAX_MODE_INT;
+ wide_int w = wide_int::from (std::make_pair (x, oldmode),
+ GET_MODE_PRECISION (mode),
+ unsignedp ? UNSIGNED : SIGNED);
+ return immed_wide_int_const (w, mode);
canonicalization?
@@ -5301,10 +5271,10 @@ store_expr (tree exp, rtx target, int call_param_p,
bool nontemporal)
&alt_rtl);
}
- /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
- the same as that of TARGET, adjust the constant. This is needed, for
- example, in case it is a CONST_DOUBLE and we want only a word-sized
- value. */
+ /* If TEMP is a VOIDmode constant and the mode of the type of EXP is
+ not the same as that of TARGET, adjust the constant. This is
+ needed, for example, in case it is a CONST_DOUBLE or
+ CONST_WIDE_INT and we want only a word-sized value. */
if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
&& TREE_CODE (exp) != ERROR_MARK
&& GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
Why reformatting the whole comment?
@@ -9481,11 +9459,19 @@ expand_expr_real_1 (tree exp, rtx target, enum
machine_mode tmode,
return decl_rtl;
case INTEGER_CST:
- temp = immed_double_const (TREE_INT_CST_LOW (exp),
- TREE_INT_CST_HIGH (exp), mode);
-
- return temp;
-
+ {
+ tree type = TREE_TYPE (exp);
Redundant, see the beginning of the function.
+ /* One could argue that GET_MODE_PRECISION (TYPE_MODE (type))
+ should always be the same as TYPE_PRECISION (type).
+ However, it is not. Since we are converting from tree to
+ rtl, we have to expose this ugly truth here. */
+ temp = immed_wide_int_const (wide_int::from
+ (exp,
+ GET_MODE_PRECISION (TYPE_MODE (type)),
+ TYPE_SIGN (type)),
+ TYPE_MODE (type));
+ return temp;
+ }
I don't really see how one could argue that, given that there are much fewer
modes than possible type precisions, so please rewrite the comment, e.g.:
"Given that TYPE_PRECISION (type) is not always equal to
GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from the former
to the latter according to the signedness of the type".
What about a fast track where the precisions are indeed equal?
@@ -11145,8 +11131,8 @@ const_vector_from_tree (tree exp)
RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
inner);
else
- RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
- inner);
+ RTVEC_ELT (v, i)
+ = immed_wide_int_const (elt, TYPE_MODE (TREE_TYPE (elt)));
}
return gen_rtx_CONST_VECTOR (mode, v);
Why replacing inner?
--- a/gcc/machmode.def
+++ b/gcc/machmode.def
@@ -229,6 +229,9 @@ UACCUM_MODE (USA, 4, 16, 16); /* 16.16 */
UACCUM_MODE (UDA, 8, 32, 32); /* 32.32 */
UACCUM_MODE (UTA, 16, 64, 64); /* 64.64 */
+/* Should be overridden by EXTRA_MODES_FILE if wrong. */
+#define MAX_BITS_PER_UNIT 8
+
What is it for? It's not documented at all.
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -617,6 +617,12 @@ print_rtx (const_rtx in_rtx)
fprintf (outfile, " [%s]", s);
}
break;
+
+ case CONST_WIDE_INT:
+ if (! flag_simple)
+ fprintf (outfile, " ");
+ cwi_output_hex (outfile, in_rtx);
+ break;
#endif
Remove the if (! flag_simple) test.
--- a/gcc/recog.c
+++ b/gcc/recog.c
/* Returns 1 if OP is an operand that is a constant integer or constant
- floating-point number. */
+ floating-point number of MODE. */
+
+int
+const_double_operand (rtx op, enum machine_mode mode)
+{
+ return (GET_CODE (op) == CONST_DOUBLE)
+ && (GET_MODE (op) == mode || mode == VOIDmode);
+}
Can CONST_DOUBLEs still represent constant integers?
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 15a997b..a76b28b 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -345,6 +345,9 @@ DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", RTX_EXTRA)
/* numeric integer constant */
DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ)
+/* numeric integer constant */
+DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
+
I think that we should consider using a new letter here, for example W.
"" is reserved to very specific cases.
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_RTL_H
#define GCC_RTL_H
+#include <utility>
Ouch. Can't this really be avoided?
@@ -336,6 +348,14 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
1 in a VALUE or DEBUG_EXPR is NO_LOC_P in var-tracking.c. */
unsigned return_val : 1;
+ union {
+ /* RTXs are free to use up to 32 bit from here. */
+
+ /* In a CONST_WIDE_INT (aka hwivec_def), this is the number of
+ HOST_WIDE_INTs in the hwivec_def. */
+ unsigned GTY ((tag ("CONST_WIDE_INT"))) num_elem:32;
+ } GTY ((desc ("GET_CODE (&%0)"))) u2;
+
/* The first element of the operands of this rtx.
The number of operands and their types are controlled
by the `code' field, according to rtl.def. */
Why can't this be put into hwivec_def?
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
+ if (op_mode == VOIDmode)
+ {
+ /* CONST_INT have VOIDmode as the mode. We assume that all
+ the bits of the constant are significant, though, this is
+ a dangerous assumption as many times CONST_INTs are
+ created and used with garbage in the bits outside of the
+ precision of the implied mode of the const_int. */
+ op_mode = MAX_MODE_INT;
+ }
Well, if that's really dangerous, we should find another way or at least
stop the compiler before generating wrong code.
+#if TARGET_SUPPORTS_WIDE_INT == 0
+ /* This assert keeps the simplification from producing a result
+ that cannot be represented in a CONST_DOUBLE but a lot of
+ upstream callers expect that this function never fails to
+ simplify something and so you if you added this to the test
+ above the code would die later anyway. If this assert
+ happens, you just need to make the port support wide int. */
+ gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
Can't we be more forgiving here and in the other similar places?
+ /* We support any size mode. */
+ max_bitsize = MAX (GET_MODE_BITSIZE (outermode),
+ GET_MODE_BITSIZE (innermode));
max_bitsize
= MAX (GET_MODE_BITSIZE (outermode), GET_MODE_BITSIZE (innermode));