This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Sign-extend CONST_INTs within their modes
- To: gcc-patches at gcc dot gnu dot org
- Subject: Sign-extend CONST_INTs within their modes
- From: Alexandre Oliva <aoliva at redhat dot com>
- Date: 18 Mar 2001 03:24:57 -0300
- Organization: GCC Team, Red Hat
A while ago, I proposed a patch that would auto-detect the need for
64-bits HOST_WIDE_INTs, and it ended up rejected because some targets
broke with a wider-than-32-bits HOST_WIDE_INT because GCC wouldn't
sign-extend CONST_INTs as it should.
I've come up with a patch to detect occurrences of non-sign-extended
CONST_INTs, and fixed all errors it detected on a port I'm working on,
in which I enabled 64-bit HOST_WIDE_INTs. There are certainly more
bugs lurking around, in chunks of code not exercised by this port, but
I'd like to install the fixes I've found so far, and maybe the test to
detect invalid values too (it's the changes in recog.c).
This has only been tested with the new port. I intend to test it on
alpha and probably a few alpha-x-??? crosses. Suggestions?
Ok to install the codegen fixes? What about the recog changes?
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* recog.c (general_operand, immediate_operand,
nonmemory_operand): Require CONST_INTs to be sign-extended
values for their modes.
* combine.c (try_combine): Avoid generating a new set in i2
that changes the expected mode of a CONST_INT.
* expmed.c (store_bit_field): Truncate CONST_INTs.
(expand_mult_highpart, expand_divmod): Likewise.
* expr.c (convert_modes, store_field): Likewise.
* integrate.c (expand_inline_function): Use promote_mode() to
determine whether to convert_modes() of an argument as signed
or unsigned.
* optabs.c (expand_binon): Convert even CONST_INT operands to
the appropriate modes.
* stmt.c (emit_case_nodes): Convert node values to the
appropriate mode.
* unroll.c (loop_iterations): Truncate abs_diff to the mode of
the iteration variable.
* varasm.c (immed_double_const): Don't require words to be
narrower than host wide ints to properly sign-extend
CONST_INTs.
Index: gcc/recog.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/recog.c,v
retrieving revision 1.90
diff -u -p -r1.90 recog.c
--- gcc/recog.c 2001/02/18 23:56:34 1.90
+++ gcc/recog.c 2001/03/18 06:06:40
@@ -1054,6 +1054,12 @@ general_operand (op, mode)
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
+#ifdef ENABLE_RTL_CHECKING
+ if (GET_CODE (op) == CONST_INT
+ && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+ abort ();
+#endif
+
if (CONSTANT_P (op))
return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
|| mode == VOIDmode)
@@ -1237,6 +1243,12 @@ immediate_operand (op, mode)
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
+#ifdef ENABLE_RTL_CHECKING
+ if (GET_CODE (op) == CONST_INT
+ && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+ abort ();
+#endif
+
/* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
result in 0/1. It seems a safe assumption that this is
in range for everyone. */
@@ -1307,6 +1319,12 @@ nonmemory_operand (op, mode)
&& GET_MODE_CLASS (mode) != MODE_INT
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
+
+#ifdef ENABLE_RTL_CHECKING
+ if (GET_CODE (op) == CONST_INT
+ && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+ abort ();
+#endif
return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
|| mode == VOIDmode)
Index: gcc/combine.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/combine.c,v
retrieving revision 1.191
diff -u -p -r1.191 combine.c
--- gcc/combine.c 2001/03/17 17:00:23 1.191
+++ gcc/combine.c 2001/03/18 06:06:45
@@ -2267,9 +2267,25 @@ try_combine (i3, i2, i1, new_direct_jump
XEXP (*split, 0)));
#endif
- newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
- SUBST (*split, newdest);
- i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+ if (! (split_code == MULT && ! have_mult))
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ else
+ insn_code_number = -1;
+
+ /* We want to test newi2pat only if the combination for i3
+ would have worked. This prevents us from generating i2
+ as a set from a CONST_INT to a register in the wrong
+ mode, in case i3 is a comparison in a certain mode whose
+ result is in a different mode. */
+ if (insn_code_number >= 0)
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
+ SUBST (*split, newdest);
+ i2_code_number = recog_for_combine (&newi2pat, i2,
+ &new_i2_notes);
+ }
+ else
+ i2_code_number = -1;
/* If the split point was a MULT and we didn't have one before,
don't use one now. */
Index: gcc/expmed.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expmed.c,v
retrieving revision 1.76
diff -u -p -r1.76 expmed.c
--- gcc/expmed.c 2001/01/31 19:05:49 1.76
+++ gcc/expmed.c 2001/03/18 06:06:46
@@ -589,6 +589,8 @@ store_bit_field (str_rtx, bitsize, bitnu
else
value1 = gen_lowpart (maxmode, value1);
}
+ else if (GET_CODE (value) == CONST_INT)
+ value1 = GEN_INT (trunc_int_for_mode (INTVAL (value), maxmode));
else if (!CONSTANT_P (value))
/* Parse phase is supposed to make VALUE's data type
match that of the component reference, which is a type
@@ -2782,7 +2784,7 @@ expand_mult_highpart (mode, op0, cnst1,
if (size > HOST_BITS_PER_WIDE_INT)
abort ();
- op1 = GEN_INT (cnst1);
+ op1 = GEN_INT (trunc_int_for_mode (cnst1, mode));
if (GET_MODE_BITSIZE (wider_mode) <= HOST_BITS_PER_INT)
wide_op1 = op1;
@@ -3269,7 +3271,7 @@ expand_divmod (rem_flag, code, mode, op0
if (rem_flag && d < 0)
{
d = abs_d;
- op1 = GEN_INT (abs_d);
+ op1 = GEN_INT (trunc_int_for_mode (abs_d, compute_mode));
}
if (d == 1)
@@ -3299,7 +3301,8 @@ expand_divmod (rem_flag, code, mode, op0
t1 = copy_to_mode_reg (compute_mode, op0);
do_cmp_and_jump (t1, const0_rtx, GE,
compute_mode, label);
- expand_inc (t1, GEN_INT (abs_d - 1));
+ expand_inc (t1, GEN_INT (trunc_int_for_mode
+ (abs_d - 1, compute_mode)));
emit_label (label);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (lgup, 0),
@@ -3336,7 +3339,10 @@ expand_divmod (rem_flag, code, mode, op0
REG_EQUAL,
gen_rtx_DIV (compute_mode,
op0,
- GEN_INT (abs_d)));
+ GEN_INT
+ (trunc_int_for_mode
+ (abs_d,
+ compute_mode))));
quotient = expand_unop (compute_mode, neg_optab,
quotient, quotient, 0);
@@ -3835,8 +3841,10 @@ expand_divmod (rem_flag, code, mode, op0
ml = invert_mod2n (d >> pre_shift, size);
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (pre_shift, 0), NULL_RTX, unsignedp);
- quotient = expand_mult (compute_mode, t1, GEN_INT (ml), NULL_RTX,
- 0);
+ quotient = expand_mult (compute_mode, t1,
+ GEN_INT (trunc_int_for_mode
+ (ml, compute_mode)),
+ NULL_RTX, 0);
insn = get_last_insn ();
set_unique_reg_note (insn,
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expr.c,v
retrieving revision 1.303
diff -u -p -r1.303 expr.c
--- gcc/expr.c 2001/03/15 02:50:49 1.303
+++ gcc/expr.c 2001/03/18 06:06:49
@@ -1374,7 +1374,7 @@ convert_modes (mode, oldmode, x, unsigne
&& (val & ((HOST_WIDE_INT) 1 << (width - 1))))
val |= (HOST_WIDE_INT) (-1) << width;
- return GEN_INT (val);
+ return GEN_INT (trunc_int_for_mode (val, mode));
}
return gen_lowpart (mode, x);
@@ -5222,7 +5222,13 @@ store_field (target, bitsize, bitpos, mo
enum machine_mode tmode;
if (unsignedp)
- return expand_and (temp, GEN_INT (width_mask), NULL_RTX);
+ return expand_and (temp,
+ GEN_INT
+ (trunc_int_for_mode
+ (width_mask,
+ GET_MODE (temp) == VOIDmode
+ ? value_mode
+ : GET_MODE (temp))), NULL_RTX);
tmode = GET_MODE (temp);
if (tmode == VOIDmode)
tmode = value_mode;
Index: gcc/integrate.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/integrate.c,v
retrieving revision 1.133
diff -u -p -r1.133 integrate.c
--- gcc/integrate.c 2001/03/17 18:37:24 1.133
+++ gcc/integrate.c 2001/03/18 06:06:49
@@ -723,13 +723,26 @@ expand_inline_function (fndecl, parms, t
else if (GET_CODE (loc) != MEM)
{
if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))
- /* The mode if LOC and ARG can differ if LOC was a variable
- that had its mode promoted via PROMOTED_MODE. */
- arg_vals[i] = convert_modes (GET_MODE (loc),
- TYPE_MODE (TREE_TYPE (arg)),
- expand_expr (arg, NULL_RTX, mode,
- EXPAND_SUM),
- TREE_UNSIGNED (TREE_TYPE (formal)));
+ {
+ int unsignedp = TREE_UNSIGNED (TREE_TYPE (formal));
+ enum machine_mode pmode = TYPE_MODE (TREE_TYPE (formal));
+
+#ifdef PROMOTE_FUNCTION_ARGS
+ pmode = promote_mode (TREE_TYPE (formal), pmode,
+ &unsignedp, 1);
+#endif
+
+ if (GET_MODE (loc) != pmode)
+ abort ();
+
+ /* The mode if LOC and ARG can differ if LOC was a variable
+ that had its mode promoted via PROMOTED_MODE. */
+ arg_vals[i] = convert_modes (pmode,
+ TYPE_MODE (TREE_TYPE (arg)),
+ expand_expr (arg, NULL_RTX, mode,
+ EXPAND_SUM),
+ unsignedp);
+ }
else
arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
}
Index: gcc/optabs.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/optabs.c,v
retrieving revision 1.89
diff -u -p -r1.89 optabs.c
--- gcc/optabs.c 2001/03/07 19:29:36 1.89
+++ gcc/optabs.c 2001/03/18 06:06:50
@@ -724,15 +724,15 @@ expand_binop (mode, binoptab, op0, op1,
}
/* In case the insn wants input operands in modes different from
- the result, convert the operands. */
+ the result, convert the operands. It would seem that we
+ don't need to convert CONST_INTs, but we do, so that they're
+ a properly sign-extended for their modes. */
- if (GET_MODE (op0) != VOIDmode
- && GET_MODE (op0) != mode0
+ if (GET_MODE (op0) != mode0
&& mode0 != VOIDmode)
xop0 = convert_to_mode (mode0, xop0, unsignedp);
- if (GET_MODE (xop1) != VOIDmode
- && GET_MODE (xop1) != mode1
+ if (GET_MODE (xop1) != mode1
&& mode1 != VOIDmode)
xop1 = convert_to_mode (mode1, xop1, unsignedp);
@@ -4296,7 +4296,9 @@ expand_fix (to, from, unsignedp)
NULL_RTX, 0, OPTAB_LIB_WIDEN);
expand_fix (to, target, 0);
target = expand_binop (GET_MODE (to), xor_optab, to,
- GEN_INT ((HOST_WIDE_INT) 1 << (bitsize - 1)),
+ GEN_INT (trunc_int_for_mode
+ ((HOST_WIDE_INT) 1 << (bitsize - 1),
+ GET_MODE (to))),
to, 1, OPTAB_LIB_WIDEN);
if (target != to)
Index: gcc/stmt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/stmt.c,v
retrieving revision 1.187
diff -u -p -r1.187 stmt.c
--- gcc/stmt.c 2001/03/15 02:50:49 1.187
+++ gcc/stmt.c 2001/03/18 06:06:51
@@ -6153,6 +6153,7 @@ emit_case_nodes (index, node, default_la
/* If INDEX has an unsigned type, we must make unsigned branches. */
int unsignedp = TREE_UNSIGNED (index_type);
enum machine_mode mode = GET_MODE (index);
+ enum machine_mode imode = TYPE_MODE (index_type);
/* See if our parents have already tested everything for us.
If they have, emit an unconditional jump for this node. */
@@ -6164,7 +6165,11 @@ emit_case_nodes (index, node, default_la
/* Node is single valued. First see if the index expression matches
this node and then check our children, if any. */
- do_jump_if_equal (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
+ do_jump_if_equal (index,
+ convert_modes (mode, imode,
+ expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
label_rtx (node->code_label), unsignedp);
if (node->right != 0 && node->left != 0)
@@ -6178,8 +6183,11 @@ emit_case_nodes (index, node, default_la
if (node_is_bounded (node->right, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
label_rtx (node->right->code_label));
emit_case_nodes (index, node->left, default_label, index_type);
@@ -6188,8 +6196,11 @@ emit_case_nodes (index, node, default_la
else if (node_is_bounded (node->left, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
LT, NULL_RTX, mode, unsignedp, 0,
label_rtx (node->left->code_label));
emit_case_nodes (index, node->right, default_label, index_type);
@@ -6204,8 +6215,11 @@ emit_case_nodes (index, node, default_la
/* See if the value is on the right. */
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
label_rtx (test_label));
@@ -6236,8 +6250,11 @@ emit_case_nodes (index, node, default_la
if (!node_has_low_bound (node, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
LT, NULL_RTX, mode, unsignedp, 0,
default_label);
}
@@ -6249,8 +6266,11 @@ emit_case_nodes (index, node, default_la
since we haven't ruled out the numbers less than
this node's value. So handle node->right explicitly. */
do_jump_if_equal (index,
- expand_expr (node->right->low, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->right->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
label_rtx (node->right->code_label), unsignedp);
}
@@ -6276,9 +6296,12 @@ emit_case_nodes (index, node, default_la
{
if (!node_has_high_bound (node, index_type))
{
- emit_cmp_and_jump_insns (index, expand_expr (node->high,
- NULL_RTX,
- VOIDmode, 0),
+ emit_cmp_and_jump_insns (index,
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
default_label);
}
@@ -6290,8 +6313,11 @@ emit_case_nodes (index, node, default_la
since we haven't ruled out the numbers less than
this node's value. So handle node->left explicitly. */
do_jump_if_equal (index,
- expand_expr (node->left->low, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->left->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
label_rtx (node->left->code_label), unsignedp);
}
}
@@ -6313,8 +6339,12 @@ emit_case_nodes (index, node, default_la
if (node_is_bounded (node->right, index_type))
/* Right hand node is fully bounded so we can eliminate any
testing and branch directly to the target code. */
- emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ emit_cmp_and_jump_insns (index,
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
label_rtx (node->right->code_label));
else
@@ -6324,16 +6354,23 @@ emit_case_nodes (index, node, default_la
test_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
label_rtx (test_label));
}
/* Value belongs to this node or to the left-hand subtree. */
- emit_cmp_and_jump_insns (index, expand_expr (node->low, NULL_RTX,
- VOIDmode, 0),
+ emit_cmp_and_jump_insns (index,
+ convert_modes
+ (mode, imode,
+ expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GE, NULL_RTX, mode, unsignedp, 0,
label_rtx (node->code_label));
@@ -6360,16 +6397,23 @@ emit_case_nodes (index, node, default_la
if (!node_has_low_bound (node, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->low, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
LT, NULL_RTX, mode, unsignedp, 0,
default_label);
}
/* Value belongs to this node or to the right-hand subtree. */
- emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ emit_cmp_and_jump_insns (index,
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
LE, NULL_RTX, mode, unsignedp, 0,
label_rtx (node->code_label));
@@ -6383,8 +6427,11 @@ emit_case_nodes (index, node, default_la
if (!node_has_high_bound (node, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
default_label);
}
@@ -6392,8 +6439,11 @@ emit_case_nodes (index, node, default_la
/* Value belongs to this node or to the left-hand subtree. */
emit_cmp_and_jump_insns (index,
- expand_expr (node->low, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GE, NULL_RTX, mode, unsignedp, 0,
label_rtx (node->code_label));
@@ -6409,8 +6459,11 @@ emit_case_nodes (index, node, default_la
if (!node_has_high_bound (node, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
GT, NULL_RTX, mode, unsignedp, 0,
default_label);
}
@@ -6418,8 +6471,11 @@ emit_case_nodes (index, node, default_la
if (!node_has_low_bound (node, index_type))
{
emit_cmp_and_jump_insns (index,
- expand_expr (node->low, NULL_RTX,
- VOIDmode, 0),
+ convert_modes
+ (mode, imode,
+ expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
LT, NULL_RTX, mode, unsignedp, 0,
default_label);
}
Index: gcc/unroll.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/unroll.c,v
retrieving revision 1.125
diff -u -p -r1.125 unroll.c
--- gcc/unroll.c 2001/01/25 09:28:55 1.125
+++ gcc/unroll.c 2001/03/18 06:06:52
@@ -3962,6 +3962,8 @@ loop_iterations (loop)
else
abort ();
+ abs_diff = trunc_int_for_mode (abs_diff, GET_MODE (iteration_var));
+
/* For NE tests, make sure that the iteration variable won't miss
the final value. If abs_diff mod abs_incr is not zero, then the
iteration variable will overflow before the loop exits, and we
Index: gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/varasm.c,v
retrieving revision 1.166
diff -u -p -r1.166 varasm.c
--- gcc/varasm.c 2001/03/15 09:58:58 1.166
+++ gcc/varasm.c 2001/03/18 06:06:52
@@ -1989,7 +1989,7 @@ immed_double_const (i0, i1, mode)
represented as a 64 bit value -1, and not as 0x00000000ffffffff.
The later confuses the sparc backend. */
- if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+ if (width < HOST_BITS_PER_WIDE_INT
&& (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
i0 |= ((HOST_WIDE_INT) (-1) << width);
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me