This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[cond-optab] Fix doubleword shifts
- From: Paolo Bonzini <bonzini at gnu dot org>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 27 Mar 2009 11:15:24 -0400
- Subject: [cond-optab] Fix doubleword shifts
This patch cures a failure in building libgcc on MMIX, Alpha and other
targets that lack a cbranchsi4 pattern (only cbranchdi4).
The reason of the problem is that I had overlooked that compare_from_rtx
can widen its operands. This in retrospect is quite obvious; I missed
that because it only happens when expand (as opposed to if-conversion)
generates conditional moves: in particular this is the case with
doubleword shifts.
To fix this, I modified prepare_cmp_insn to use an optab_methods argument.
I also simplified the calling convention so that it plugs better in
functions that used to call compare_from_rtx.
Previously, the widening done by compare_from_rtx could in principle
leave partly formed sequences in the RTL stream, because compare_from_rtx
was not wrapped in start_sequence/end_sequence. It probably never
happened, but I cleaned this up too.
Paolo
2009-03-26 Paolo Bonzini <bonzini@gnu.org>
* optabs.c (prepare_float_lib_cmp): Return an rtx and a machine mode.
Accept other parameters by value.
(prepare_cmp_insn): Return an rtx and a machine mode. Accept
other parameters by value. Try to widen operands here based on
an optab_methods argument.
(emit_cmp_and_jump_insn_1): Remove widening loop.
(emit_cmp_and_jump_insns): Adjust call to prepare_cmp_insn, remove
obsolete assertion.
(emit_conditional_move, emit_conditional_add, emit_conditional_trap):
Use new prepare_cmp_insn.
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c (branch cond-optab)
+++ gcc/optabs.c (working copy)
@@ -94,8 +94,8 @@ enum insn_code movcc_gen_code[NUM_MACHIN
enum insn_code vcond_gen_code[NUM_MACHINE_MODES];
enum insn_code vcondu_gen_code[NUM_MACHINE_MODES];
-static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
- enum machine_mode *, int *);
+static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *,
+ enum machine_mode *);
static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
/* Debug facility for use in GDB. */
@@ -3995,7 +3995,7 @@ can_compare_p (enum rtx_code code, enum
*PMODE is the mode of the inputs (in case they are const_int).
*PUNSIGNEDP nonzero says that the operands are unsigned;
- this matters if they need to be widened.
+ this matters if they need to be widened (as given by METHODS).
If they have mode BLKmode, then SIZE specifies the size of both operands.
@@ -4008,14 +4008,18 @@ can_compare_p (enum rtx_code code, enum
comparisons must have already been folded. */
static void
-prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
- enum machine_mode *pmode, int *punsignedp,
- enum can_compare_purpose purpose)
+prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
+ int unsignedp, enum optab_methods methods,
+ rtx *ptest, enum machine_mode *pmode)
{
enum machine_mode mode = *pmode;
- rtx x = *px, y = *py;
- int unsignedp = *punsignedp;
- rtx libfunc;
+ rtx libfunc, test;
+ enum machine_mode cmp_mode;
+ enum mode_class mclass;
+
+ /* The other methods are not needed. */
+ gcc_assert (methods == OPTAB_DIRECT || methods == OPTAB_WIDEN
+ || methods == OPTAB_LIB_WIDEN);
#ifdef HAVE_cc0
/* Make sure if we have a canonical comparison. The RTL
@@ -4032,7 +4036,7 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
if (mode == BLKmode)
{
- enum machine_mode cmp_mode, result_mode;
+ enum machine_mode result_mode;
enum insn_code cmp_code;
tree length_type;
rtx libfunc;
@@ -4068,12 +4072,14 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
size = convert_to_mode (cmp_mode, size, 1);
emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign));
- *px = result;
- *py = const0_rtx;
- *pmode = result_mode;
+ *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, result, const0_rtx);
+ *pmode = result_mode;
return;
}
+ if (methods != OPTAB_LIB && methods != OPTAB_LIB_WIDEN)
+ goto fail;
+
/* Otherwise call a library function, memcmp. */
libfunc = memcmp_libfunc;
length_type = sizetype;
@@ -4087,8 +4093,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
XEXP (x, 0), Pmode,
XEXP (y, 0), Pmode,
size, cmp_mode);
- *px = result;
- *py = const0_rtx;
+
+ *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, result, const0_rtx);
*pmode = result_mode;
return;
}
@@ -4103,15 +4109,43 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
y = force_reg (mode, y);
}
- *px = x;
- *py = y;
if (GET_MODE_CLASS (mode) == MODE_CC)
{
- gcc_assert (can_compare_p (*pcomparison, CCmode, purpose));
+ gcc_assert (can_compare_p (comparison, CCmode, ccp_jump));
+ *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
return;
}
- else if (can_compare_p (*pcomparison, mode, purpose))
- return;
+
+ mclass = GET_MODE_CLASS (mode);
+ test = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
+ cmp_mode = mode;
+ do
+ {
+ enum insn_code icode;
+ icode = optab_handler (cbranch_optab, cmp_mode)->insn_code;
+ if (icode != CODE_FOR_nothing
+ && insn_data[icode].operand[0].predicate (test, VOIDmode))
+ {
+ x = prepare_operand (icode, x, 1, mode, cmp_mode, unsignedp);
+ y = prepare_operand (icode, y, 2, mode, cmp_mode, unsignedp);
+ if (x && y)
+ {
+ XEXP (test, 0) = x;
+ XEXP (test, 1) = y;
+ *ptest = test;
+ *pmode = cmp_mode;
+ return;
+ }
+ }
+
+ if (methods == OPTAB_DIRECT || !CLASS_HAS_WIDER_MODES_P (mclass))
+ break;
+ cmp_mode = GET_MODE_WIDER_MODE (cmp_mode);
+ }
+ while (cmp_mode != VOIDmode);
+
+ if (methods != OPTAB_LIB_WIDEN)
+ goto fail;
/* Handle a lib call just for the mode we are using. */
libfunc = optab_libfunc (cmp_optab, mode);
@@ -4140,22 +4174,28 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
case. For unsigned comparisons always compare against 1 after
biasing the unbiased result by adding 1. This gives us a way to
represent LTU. */
- *px = result;
- *pmode = word_mode;
- *py = const1_rtx;
+ x = result;
+ y = const1_rtx;
if (!TARGET_LIB_INT_CMP_BIASED)
{
- if (*punsignedp)
- *px = plus_constant (result, 1);
+ if (unsignedp)
+ x = plus_constant (result, 1);
else
- *py = const0_rtx;
+ y = const0_rtx;
}
+
+ *ptest = gen_rtx_fmt_ee (comparison, word_mode, x, y);
+ *pmode = word_mode;
return;
}
gcc_assert (SCALAR_FLOAT_MODE_P (mode));
- prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
+ prepare_float_lib_cmp (x, y, comparison, ptest, pmode);
+ return;
+
+ fail:
+ *ptest = NULL_RTX;
}
/* Before emitting an insn with code ICODE, make sure that X, which is going
@@ -4182,48 +4222,23 @@ prepare_operand (int icode, rtx x, int o
}
/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
- we can do the comparison.
- The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
- be NULL_RTX which indicates that only a comparison is to be generated. */
+ we can do the branch. */
static void
-emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
- enum rtx_code comparison, int unsignedp, rtx label)
+emit_cmp_and_jump_insn_1 (rtx test, enum machine_mode mode, rtx label)
{
- rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
- enum mode_class mclass = GET_MODE_CLASS (mode);
- enum machine_mode wider_mode = mode;
-
- do
- {
- enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : wider_mode;
- enum insn_code icode;
- PUT_MODE (test, wider_mode);
-
- icode = optab_handler (cbranch_optab, optab_mode)->insn_code;
-
- if (icode != CODE_FOR_nothing
- && insn_data[icode].operand[0].predicate (test, wider_mode))
- {
- x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
- y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
-
- /* Rebuild test so as to give freedom to the machine description
- whether to use operands[1]/operands[2] or not. */
- test = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
- gcc_assert (insn_data[icode].operand[0].predicate (test, VOIDmode));
- emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
- return;
- }
+ enum machine_mode optab_mode;
+ enum mode_class mclass;
+ enum insn_code icode;
- if (!CLASS_HAS_WIDER_MODES_P (mclass))
- break;
+ mclass = GET_MODE_CLASS (mode);
+ optab_mode = (mclass == MODE_CC) ? CCmode : mode;
+ icode = optab_handler (cbranch_optab, optab_mode)->insn_code;
- wider_mode = GET_MODE_WIDER_MODE (wider_mode);
- }
- while (wider_mode != VOIDmode);
+ gcc_assert (icode != CODE_FOR_nothing);
+ gcc_assert (insn_data[icode].operand[0].predicate (test, VOIDmode));
- gcc_unreachable ();
+ emit_jump_insn (GEN_FCN (icode) (test, XEXP (test, 0), XEXP (test, 1), label));
}
/* Generate code to compare X with Y so that the condition codes are
@@ -4248,16 +4263,11 @@ emit_cmp_and_jump_insns (rtx x, rtx y, e
enum machine_mode mode, int unsignedp, rtx label)
{
rtx op0 = x, op1 = y;
+ rtx test;
/* Swap operands and condition to ensure canonical RTL. */
if (swap_commutative_operands_p (x, y))
{
- /* If we're not emitting a branch, callers are required to pass
- operands in an order conforming to canonical RTL. We relax this
- for commutative comparisons so callers using EQ don't need to do
- swapping by hand. */
- gcc_assert (label || (comparison == swap_condition (comparison)));
-
op0 = y, op1 = x;
comparison = swap_condition (comparison);
}
@@ -4272,9 +4282,9 @@ emit_cmp_and_jump_insns (rtx x, rtx y, e
if (unsignedp)
comparison = unsigned_condition (comparison);
- prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
- ccp_jump);
- emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
+ prepare_cmp_insn (op0, op1, comparison, size, unsignedp, OPTAB_LIB_WIDEN,
+ &test, &mode);
+ emit_cmp_and_jump_insn_1 (test, mode, label);
}
@@ -4282,14 +4292,11 @@ emit_cmp_and_jump_insns (rtx x, rtx y, e
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */
static void
-prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
- enum machine_mode *pmode, int *punsignedp)
+prepare_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison,
+ rtx *ptest, enum machine_mode *pmode)
{
- enum rtx_code comparison = *pcomparison;
enum rtx_code swapped = swap_condition (comparison);
enum rtx_code reversed = reverse_condition_maybe_unordered (comparison);
- rtx x = *px;
- rtx y = *py;
enum machine_mode orig_mode = GET_MODE (x);
enum machine_mode mode, cmp_mode;
rtx value, target, insns, equiv;
@@ -4399,11 +4406,8 @@ prepare_float_lib_cmp (rtx *px, rtx *py,
|| FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
comparison = reversed_p ? EQ : NE;
- *px = target;
- *py = const0_rtx;
+ *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, target, const0_rtx);
*pmode = cmp_mode;
- *pcomparison = comparison;
- *punsignedp = 0;
}
/* Generate code to indirectly jump to a location given in the rtx LOC. */
@@ -4515,14 +4519,26 @@ emit_conditional_move (rtx target, enum
return NULL_RTX;
do_pending_stack_adjust ();
- insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+ start_sequence ();
+ prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
+ GET_CODE (comparison), NULL_RTX, false, OPTAB_WIDEN,
+ &comparison, &cmode);
+ if (!comparison)
+ insn = NULL_RTX;
+ else
+ insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
/* If that failed, then give up. */
if (insn == 0)
- return 0;
+ {
+ end_sequence ();
+ return 0;
+ }
emit_insn (insn);
-
+ insn = get_insns ();
+ end_sequence ();
+ emit_insn (insn);
if (subtarget != target)
convert_move (target, subtarget, 0);
@@ -4642,14 +4658,26 @@ emit_conditional_add (rtx target, enum r
return NULL_RTX;
do_pending_stack_adjust ();
- insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+ start_sequence ();
+ prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
+ GET_CODE (comparison), NULL_RTX, false, OPTAB_WIDEN,
+ &comparison, &cmode);
+ if (!comparison)
+ insn = NULL_RTX;
+ else
+ insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
/* If that failed, then give up. */
if (insn == 0)
- return 0;
+ {
+ end_sequence ();
+ return 0;
+ }
emit_insn (insn);
-
+ insn = get_insns ();
+ end_sequence ();
+ emit_insn (insn);
if (subtarget != target)
convert_move (target, subtarget, 0);
@@ -6653,18 +6681,26 @@ gen_cond_trap (enum rtx_code code, rtx o
if (!insn_data[icode].operand[3].predicate (tcode, VOIDmode))
return 0;
+ do_pending_stack_adjust ();
start_sequence ();
- op1 = prepare_operand (icode, op1, 1, mode, mode, 0);
- op2 = prepare_operand (icode, op2, 2, mode, mode, 0);
- if (!op1 || !op2)
+ prepare_cmp_insn (op1, op2, code, NULL_RTX, false, OPTAB_DIRECT,
+ &trap_rtx, &mode);
+ if (!trap_rtx)
+ insn = NULL_RTX;
+ else
+ insn = GEN_FCN (icode) (trap_rtx, XEXP (trap_rtx, 0), XEXP (trap_rtx, 1),
+ tcode);
+
+ /* If that failed, then give up. */
+ if (insn == 0)
{
end_sequence ();
return 0;
}
- trap_rtx = gen_rtx_fmt_ee (code, mode, op1, op2);
- insn = GEN_FCN (icode) (trap_rtx, op1, op2, tcode);
- end_sequence ();
+ emit_insn (insn);
+ insn = get_insns ();
+ end_sequence ();
return insn;
}