enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
#endif
-static int add_equal_note PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx));
-static rtx widen_operand PARAMS ((rtx, enum machine_mode,
- enum machine_mode, int, int));
-static int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx,
- rtx, rtx, enum machine_mode,
- int, enum optab_methods,
- enum mode_class, optab));
-static int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx,
- rtx, rtx, enum machine_mode,
- int, enum optab_methods,
- enum mode_class, optab));
-static void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
- enum machine_mode *, int *,
- enum can_compare_purpose));
-static enum insn_code can_fix_p PARAMS ((enum machine_mode, enum machine_mode,
- int, int *));
-static enum insn_code can_float_p PARAMS ((enum machine_mode,
- enum machine_mode,
- int));
-static rtx ftruncify PARAMS ((rtx));
-static optab new_optab PARAMS ((void));
-static inline optab init_optab PARAMS ((enum rtx_code));
-static inline optab init_optabv PARAMS ((enum rtx_code));
-static void init_libfuncs PARAMS ((optab, int, int, const char *, int));
-static void init_integral_libfuncs PARAMS ((optab, const char *, int));
-static void init_floating_libfuncs PARAMS ((optab, const char *, int));
-#ifdef HAVE_conditional_trap
-static void init_traps PARAMS ((void));
+/* The insn generating function can not take an rtx_code argument.
+ TRAP_RTX is used as an rtx argument. Its code is replaced with
+ the code to be used in the trap insn and all other fields are ignored. */
+static GTY(()) rtx trap_rtx;
+
+static int add_equal_note (rtx, rtx, enum rtx_code, rtx, rtx);
+static rtx widen_operand (rtx, enum machine_mode, enum machine_mode, int,
+ int);
+static int expand_cmplxdiv_straight (rtx, rtx, rtx, rtx, rtx, rtx,
+ enum machine_mode, int,
+ enum optab_methods, enum mode_class,
+ optab);
+static int expand_cmplxdiv_wide (rtx, rtx, rtx, rtx, rtx, rtx,
+ enum machine_mode, int, enum optab_methods,
+ enum mode_class, optab);
+static void prepare_cmp_insn (rtx *, rtx *, enum rtx_code *, rtx,
+ enum machine_mode *, int *,
+ enum can_compare_purpose);
+static enum insn_code can_fix_p (enum machine_mode, enum machine_mode, int,
+ int *);
+static enum insn_code can_float_p (enum machine_mode, enum machine_mode, int);
+static rtx ftruncify (rtx);
+static optab new_optab (void);
+static inline optab init_optab (enum rtx_code);
+static inline optab init_optabv (enum rtx_code);
+static void init_libfuncs (optab, int, int, const char *, int);
+static void init_integral_libfuncs (optab, const char *, int);
+static void init_floating_libfuncs (optab, const char *, int);
+static void emit_cmp_and_jump_insn_1 (rtx, rtx, enum machine_mode,
+ enum rtx_code, int, rtx);
+static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
+ enum machine_mode *, int *);
+static rtx expand_vector_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
+ enum optab_methods);
+static rtx expand_vector_unop (enum machine_mode, optab, rtx, rtx, int);
+static rtx widen_clz (enum machine_mode, rtx, rtx);
+static rtx expand_parity (enum machine_mode, rtx, rtx);
+
+#ifndef HAVE_conditional_trap
+#define HAVE_conditional_trap 0
+#define gen_conditional_trap(a,b) (abort (), NULL_RTX)
#endif
-static void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
- enum rtx_code, int, rtx));
-static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
- enum machine_mode *, int *));
-static rtx expand_vector_binop PARAMS ((enum machine_mode, optab,
- rtx, rtx, rtx, int,
- enum optab_methods));
-static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
- int));
-static rtx widen_clz PARAMS ((enum machine_mode, rtx, rtx));
-static rtx expand_parity PARAMS ((enum machine_mode, rtx, rtx));
\f
/* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to
the result of operation CODE applied to OP0 (and OP1 if it is a binary
again, ensuring that TARGET is not one of the operands. */
static int
-add_equal_note (insns, target, code, op0, op1)
- rtx insns;
- rtx target;
- enum rtx_code code;
- rtx op0, op1;
+add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
{
rtx last_insn, insn, set;
rtx note;
return 1;
if (! rtx_equal_p (SET_DEST (set), target)
- /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
- SUBREG. */
+ /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside it. */
&& (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
- || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
- target)))
+ || ! rtx_equal_p (XEXP (SET_DEST (set), 0), target)))
return 1;
/* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
\f
/* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP
says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need
- not actually do a sign-extend or zero-extend, but can leave the
+ not actually do a sign-extend or zero-extend, but can leave the
higher-order bits of the result rtx undefined, for example, in the case
of logical operations, but not right shifts. */
static rtx
-widen_operand (op, mode, oldmode, unsignedp, no_extend)
- rtx op;
- enum machine_mode mode, oldmode;
- int unsignedp;
- int no_extend;
+widen_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
+ int unsignedp, int no_extend)
{
rtx result;
/* Generate code to perform a straightforward complex divide. */
static int
-expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
- unsignedp, methods, class, binoptab)
- rtx real0, real1, imag0, imag1, realr, imagr;
- enum machine_mode submode;
- int unsignedp;
- enum optab_methods methods;
- enum mode_class class;
- optab binoptab;
+expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
+ rtx realr, rtx imagr, enum machine_mode submode,
+ int unsignedp, enum optab_methods methods,
+ enum mode_class class, optab binoptab)
{
rtx divisor;
rtx real_t, imag_t;
optab this_sub_optab = sub_optab;
optab this_neg_optab = neg_optab;
optab this_mul_optab = smul_optab;
-
+
if (binoptab == sdivv_optab)
{
this_add_optab = addv_optab;
/* Calculate the dividend. */
real_t = expand_binop (submode, this_mul_optab, real0, real1,
NULL_RTX, unsignedp, methods);
-
+
imag_t = expand_binop (submode, this_mul_optab, real0, imag1,
NULL_RTX, unsignedp, methods);
real_t = expand_binop (submode, this_add_optab, temp1, temp2,
NULL_RTX, unsignedp, methods);
-
+
temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
NULL_RTX, unsignedp, methods);
/* Generate code to perform a wide-input-range-acceptable complex divide. */
static int
-expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
- unsignedp, methods, class, binoptab)
- rtx real0, real1, imag0, imag1, realr, imagr;
- enum machine_mode submode;
- int unsignedp;
- enum optab_methods methods;
- enum mode_class class;
- optab binoptab;
+expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1, rtx realr,
+ rtx imagr, enum machine_mode submode, int unsignedp,
+ enum optab_methods methods, enum mode_class class,
+ optab binoptab)
{
rtx ratio, divisor;
rtx real_t, imag_t;
this_neg_optab = negv_optab;
this_mul_optab = smulv_optab;
}
-
+
/* Don't fetch these from memory more than once. */
real0 = force_reg (submode, real0);
real1 = force_reg (submode, real1);
the operation to perform, not an optab pointer. All other
arguments are the same. */
rtx
-expand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
- enum machine_mode mode;
- enum rtx_code code;
- rtx op0, op1;
- rtx target;
- int unsignedp;
- enum optab_methods methods;
+expand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
+ rtx op1, rtx target, int unsignedp,
+ enum optab_methods methods)
{
optab binop = code_to_optab[(int) code];
if (binop == 0)
this may or may not be TARGET. */
rtx
-expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
- enum machine_mode mode;
- optab binoptab;
- rtx op0, op1;
- rtx target;
- int unsignedp;
- enum optab_methods methods;
+expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
+ rtx target, int unsignedp, enum optab_methods methods)
{
enum optab_methods next_methods
= (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
if (flag_force_mem)
{
- op0 = force_not_mem (op0);
- op1 = force_not_mem (op1);
+ /* Load duplicate non-volatile operands once. */
+ if (rtx_equal_p (op0, op1) && ! volatile_refs_p (op0))
+ {
+ op0 = force_not_mem (op0);
+ op1 = op0;
+ }
+ else
+ {
+ op0 = force_not_mem (op0);
+ op1 = force_not_mem (op1);
+ }
}
/* If subtracting an integer constant, convert this into an addition of
if (inter != 0)
inter = expand_binop (word_mode, binoptab, outof_input,
op1, outof_target, unsignedp, next_methods);
-
+
if (inter != 0 && inter != outof_target)
emit_move_insn (outof_target, inter);
}
if (i > 0)
{
rtx newx;
-
+
/* Add/subtract previous carry to main result. */
newx = expand_binop (word_mode,
normalizep == 1 ? binoptab : otheroptab,
}
carry_in = carry_out;
- }
+ }
if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
{
- if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+ || ! rtx_equal_p (target, xtarget))
{
rtx temp = emit_move_insn (target, xtarget);
set_unique_reg_note (temp,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_fmt_ee (binoptab->code, mode,
copy_rtx (xop0),
copy_rtx (xop1)));
/* If we want to multiply two two-word values and have normal and widening
multiplies of single-word values, we can do this with three smaller
multiplications. Note that we do not make a REG_NO_CONFLICT block here
- because we are not operating on one word at a time.
+ because we are not operating on one word at a time.
The multiplication proceeds as follows:
_______________________
emit_move_insn (product_high, temp);
if (temp != 0)
- temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
+ temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
NULL_RTX, 0, OPTAB_DIRECT);
if (temp != 0)
{
temp = emit_move_insn (product, product);
set_unique_reg_note (temp,
- REG_EQUAL,
+ REG_EQUAL,
gen_rtx_fmt_ee (MULT, mode,
copy_rtx (op0),
copy_rtx (op1)));
rtx equiv_value;
int ok = 0;
- /* Find the correct mode for the real and imaginary parts */
+ /* Find the correct mode for the real and imaginary parts. */
enum machine_mode submode = GET_MODE_INNER(mode);
if (submode == BLKmode)
temp1 = expand_binop (submode, binoptab, real0, imag1,
NULL_RTX, unsignedp, methods);
- temp2 = expand_binop (submode, binoptab, real1, imag0,
- NULL_RTX, unsignedp, methods);
+ /* Avoid expanding redundant multiplication for the common
+ case of squaring a complex number. */
+ if (rtx_equal_p (real0, real1) && rtx_equal_p (imag0, imag1))
+ temp2 = temp1;
+ else
+ temp2 = expand_binop (submode, binoptab, real1, imag0,
+ NULL_RTX, unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
break;
case DIV:
/* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
-
+
if (imag1 == 0)
{
/* (a+ib) / (c+i0) = (a/c) + i(b/c) */
}
}
break;
-
+
default:
abort ();
}
copy_rtx (op0), copy_rtx (op1));
else
equiv_value = 0;
-
+
emit_no_conflict_block (seq, target, op0, op1, equiv_value);
-
+
return target;
}
}
/* Like expand_binop, but for open-coding vectors binops. */
static rtx
-expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
- enum machine_mode mode;
- optab binoptab;
- rtx op0, op1;
- rtx target;
- int unsignedp;
- enum optab_methods methods;
+expand_vector_binop (enum machine_mode mode, optab binoptab, rtx op0,
+ rtx op1, rtx target, int unsignedp,
+ enum optab_methods methods)
{
enum machine_mode submode, tmode;
int size, elts, subsize, subbitsize, i;
/* Like expand_unop but for open-coding vector unops. */
static rtx
-expand_vector_unop (mode, unoptab, op0, target, unsignedp)
- enum machine_mode mode;
- optab unoptab;
- rtx op0;
- rtx target;
- int unsignedp;
+expand_vector_unop (enum machine_mode mode, optab unoptab, rtx op0,
+ rtx target, int unsignedp)
{
enum machine_mode submode, tmode;
int size, elts, subsize, subbitsize, i;
/* Avoid infinite recursion when an
error has left us with the wrong mode. */
&& GET_MODE (op0) == mode)
- {
+ {
rtx temp;
temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
target, unsignedp, OPTAB_DIRECT);
of an unsigned wider operation, since the result would be the same. */
rtx
-sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
- enum machine_mode mode;
- optab uoptab, soptab;
- rtx op0, op1, target;
- int unsignedp;
- enum optab_methods methods;
+sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
+ rtx op0, rtx op1, rtx target, int unsignedp,
+ enum optab_methods methods)
{
rtx temp;
optab direct_optab = unsignedp ? uoptab : soptab;
Returns 1 if this operation can be performed; 0 if not. */
int
-expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
- optab binoptab;
- rtx op0, op1;
- rtx targ0, targ1;
- int unsignedp;
+expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
+ int unsignedp)
{
enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
enum mode_class class;
if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
|| ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
abort ();
-
+
pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
if (pat)
{
the operation to perform, not an optab pointer. All other
arguments are the same. */
rtx
-expand_simple_unop (mode, code, op0, target, unsignedp)
- enum machine_mode mode;
- enum rtx_code code;
- rtx op0;
- rtx target;
- int unsignedp;
+expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
+ rtx target, int unsignedp)
{
optab unop = code_to_optab[(int) code];
if (unop == 0)
as
(clz:wide (zero_extend:wide x)) - ((width wide) - (width narrow)). */
static rtx
-widen_clz (mode, op0, target)
- enum machine_mode mode;
- rtx op0;
- rtx target;
+widen_clz (enum machine_mode mode, rtx op0, rtx target)
{
enum mode_class class = GET_MODE_CLASS (mode);
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
/* Try calculating (parity x) as (and (popcount x) 1), where
popcount can also be done in a wider mode. */
static rtx
-expand_parity (mode, op0, target)
- enum machine_mode mode;
- rtx op0;
- rtx target;
+expand_parity (enum machine_mode mode, rtx op0, rtx target)
{
enum mode_class class = GET_MODE_CLASS (mode);
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
this may or may not be TARGET. */
rtx
-expand_unop (mode, unoptab, op0, target, unsignedp)
- enum machine_mode mode;
- optab unoptab;
- rtx op0;
- rtx target;
- int unsignedp;
+expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
+ int unsignedp)
{
enum mode_class class;
enum machine_mode wider_mode;
}
emit_insn (pat);
-
+
return temp;
}
else
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
-
+
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
rtx x;
rtx seq;
- /* Find the correct mode for the real and imaginary parts */
+ /* Find the correct mode for the real and imaginary parts. */
enum machine_mode submode = GET_MODE_INNER (mode);
if (submode == BLKmode)
if (target == 0)
target = gen_reg_rtx (mode);
-
+
start_sequence ();
target_piece = gen_imagpart (submode, target);
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
-
+
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
/* If there is no negate operation, try doing a subtract from zero.
The US Software GOFAST library needs this. */
if (unoptab->code == NEG)
- {
+ {
rtx temp;
temp = expand_binop (mode,
unoptab == negv_optab ? subv_optab : sub_optab,
if (temp)
return temp;
}
-
+
return 0;
}
\f
*/
rtx
-expand_abs (mode, op0, target, result_unsignedp, safe)
- enum machine_mode mode;
- rtx op0;
- rtx target;
- int result_unsignedp;
- int safe;
+expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
+ int result_unsignedp)
{
- rtx temp, op1;
+ rtx temp;
if (! flag_trapv)
result_unsignedp = 1;
return temp;
}
+ return NULL_RTX;
+}
+
+rtx
+expand_abs (enum machine_mode mode, rtx op0, rtx target,
+ int result_unsignedp, int safe)
+{
+ rtx temp, op1;
+
+ if (! flag_trapv)
+ result_unsignedp = 1;
+
+ temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
+ if (temp != 0)
+ return temp;
+
/* If that does not win, use conditional jump and negate. */
/* It is safe to use the target if it is the same
compare word by word. Rely on CSE to optimize constant cases. */
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GE, mode, ccp_jump))
- do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
+ do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
NULL_RTX, op1);
else
do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
UNSIGNEDP is relevant for complex integer modes. */
rtx
-expand_complex_abs (mode, op0, target, unsignedp)
- enum machine_mode mode;
- rtx op0;
- rtx target;
- int unsignedp;
+expand_complex_abs (enum machine_mode mode, rtx op0, rtx target,
+ int unsignedp)
{
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode;
if (pat)
{
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
- && ! add_equal_note (pat, temp, this_abs_optab->code, xop0,
+ && ! add_equal_note (pat, temp, this_abs_optab->code, xop0,
NULL_RTX))
{
delete_insns_since (last);
- return expand_unop (mode, this_abs_optab, op0, NULL_RTX,
+ return expand_unop (mode, this_abs_optab, op0, NULL_RTX,
unsignedp);
}
emit_insn (pat);
-
+
return temp;
}
else
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
- if (this_abs_optab->handlers[(int) wider_mode].insn_code
+ if (this_abs_optab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
{
rtx xop0 = op0;
the value that is stored into TARGET. */
void
-emit_unop_insn (icode, target, op0, code)
- int icode;
- rtx target;
- rtx op0;
- enum rtx_code code;
+emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
{
rtx temp;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
add_equal_note (pat, temp, code, op0, NULL_RTX);
-
+
emit_insn (pat);
if (temp != target)
INSNS is a block of code generated to perform the operation, not including
the CLOBBER and final copy. All insns that compute intermediate values
- are first emitted, followed by the block as described above.
+ are first emitted, followed by the block as described above.
TARGET, OP0, and OP1 are the output and inputs of the operations,
respectively. OP1 may be zero for a unary operation.
The final insn emitted is returned. */
rtx
-emit_no_conflict_block (insns, target, op0, op1, equiv)
- rtx insns;
- rtx target;
- rtx op0, op1;
- rtx equiv;
+emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
{
rtx prev, next, first, last, insn;
block is delimited by REG_RETVAL and REG_LIBCALL notes. */
void
-emit_libcall_block (insns, target, result, equiv)
- rtx insns;
- rtx target;
- rtx result;
- rtx equiv;
+emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
{
rtx final_dest = target;
rtx prev, next, first, last, insn;
into a MEM later. Protect the libcall block from this change. */
if (! REG_P (target) || REG_USERVAR_P (target))
target = gen_reg_rtx (GET_MODE (target));
-
+
/* If we're using non-call exceptions, a libcall corresponding to an
operation that may trap may also trap. */
if (flag_non_call_exceptions && may_trap_p (equiv))
if (GET_CODE (insn) == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-
+
if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
remove_note (insn, note);
}
if (GET_CODE (insn) == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-
+
if (note != 0)
XEXP (note, 0) = GEN_INT (-1);
else
add_insn (insn);
}
+
+ /* Some ports use a loop to copy large arguments onto the stack.
+ Don't move anything outside such a loop. */
+ if (GET_CODE (insn) == CODE_LABEL)
+ break;
}
prev = get_last_insn ();
/* Generate code to store zero in X. */
void
-emit_clr_insn (x)
- rtx x;
+emit_clr_insn (rtx x)
{
emit_move_insn (x, const0_rtx);
}
assuming it contains zero beforehand. */
void
-emit_0_to_1_insn (x)
- rtx x;
+emit_0_to_1_insn (rtx x)
{
emit_move_insn (x, const1_rtx);
}
comparison code we will be using.
??? Actually, CODE is slightly weaker than that. A target is still
- required to implement all of the normal bcc operations, but not
+ required to implement all of the normal bcc operations, but not
required to implement all (or any) of the unordered bcc operations. */
-
+
int
-can_compare_p (code, mode, purpose)
- enum rtx_code code;
- enum machine_mode mode;
- enum can_compare_purpose purpose;
+can_compare_p (enum rtx_code code, enum machine_mode mode,
+ enum can_compare_purpose purpose)
{
do
{
should perform the comparison on the modified values. */
static void
-prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
- rtx *px, *py;
- enum rtx_code *pcomparison;
- rtx size;
- enum machine_mode *pmode;
- int *punsignedp;
- enum can_compare_purpose purpose;
+prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
+ enum machine_mode *pmode, int *punsignedp,
+ enum can_compare_purpose purpose)
{
enum machine_mode mode = *pmode;
rtx x = *px, y = *py;
if (mode != BLKmode && flag_force_mem)
{
- x = force_not_mem (x);
- y = force_not_mem (y);
+ /* Load duplicate non-volatile operands once. */
+ if (rtx_equal_p (x, y) && ! volatile_refs_p (x))
+ {
+ x = force_not_mem (x);
+ y = x;
+ }
+ else
+ {
+ x = force_not_mem (x);
+ y = force_not_mem (y);
+ }
}
/* If we are inside an appropriately-short loop and one operand is an
if (size == 0)
abort ();
+#ifdef HAVE_cmpmemqi
+ if (HAVE_cmpmemqi
+ && GET_CODE (size) == CONST_INT
+ && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
+ {
+ result_mode = insn_data[(int) CODE_FOR_cmpmemqi].operand[0].mode;
+ result = gen_reg_rtx (result_mode);
+ emit_insn (gen_cmpmemqi (result, x, y, size, opalign));
+ }
+ else
+#endif
+#ifdef HAVE_cmpmemhi
+ if (HAVE_cmpmemhi
+ && GET_CODE (size) == CONST_INT
+ && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
+ {
+ result_mode = insn_data[(int) CODE_FOR_cmpmemhi].operand[0].mode;
+ result = gen_reg_rtx (result_mode);
+ emit_insn (gen_cmpmemhi (result, x, y, size, opalign));
+ }
+ else
+#endif
+#ifdef HAVE_cmpmemsi
+ if (HAVE_cmpmemsi)
+ {
+ result_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
+ result = gen_reg_rtx (result_mode);
+ size = protect_from_queue (size, 0);
+ emit_insn (gen_cmpmemsi (result, x, y,
+ convert_to_mode (SImode, size, 1),
+ opalign));
+ }
+ else
+#endif
#ifdef HAVE_cmpstrqi
if (HAVE_cmpstrqi
&& GET_CODE (size) == CONST_INT
that it is accepted by the operand predicate. Return the new value. */
rtx
-prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
- int icode;
- rtx x;
- int opnum;
- enum machine_mode mode, wider_mode;
- int unsignedp;
+prepare_operand (int icode, rtx x, int opnum, enum machine_mode mode,
+ enum machine_mode wider_mode, int unsignedp)
{
x = protect_from_queue (x, 0);
if (! (*insn_data[icode].operand[opnum].predicate)
(x, insn_data[icode].operand[opnum].mode))
- x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
+ {
+ if (no_new_pseudos)
+ return NULL_RTX;
+ x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
+ }
+
return x;
}
be NULL_RTX which indicates that only a comparison is to be generated. */
static void
-emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
- rtx x, y;
- enum machine_mode mode;
- enum rtx_code comparison;
- int unsignedp;
- rtx label;
+emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
+ enum rtx_code comparison, int unsignedp, rtx label)
{
rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
enum mode_class class = GET_MODE_CLASS (mode);
PUT_MODE (test, wider_mode);
if (label)
- {
+ {
icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
-
+
if (icode != CODE_FOR_nothing
&& (*insn_data[icode].operand[0].predicate) (test, wider_mode))
{
unsigned variant based on UNSIGNEDP to select a proper jump instruction. */
void
-emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
- rtx x, y;
- enum rtx_code comparison;
- rtx size;
- enum machine_mode mode;
- int unsignedp;
- rtx label;
+emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
+ enum machine_mode mode, int unsignedp, rtx label)
{
rtx op0 = x, op1 = y;
/* Like emit_cmp_and_jump_insns, but generate only the comparison. */
void
-emit_cmp_insn (x, y, comparison, size, mode, unsignedp)
- rtx x, y;
- enum rtx_code comparison;
- rtx size;
- enum machine_mode mode;
- int unsignedp;
+emit_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
+ enum machine_mode mode, int unsignedp)
{
emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
}
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */
static void
-prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
- rtx *px, *py;
- enum rtx_code *pcomparison;
- enum machine_mode *pmode;
- int *punsignedp;
+prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
+ enum machine_mode *pmode, int *punsignedp)
{
enum rtx_code comparison = *pcomparison;
rtx tmp;
/* Generate code to indirectly jump to a location given in the rtx LOC. */
void
-emit_indirect_jump (loc)
- rtx loc;
+emit_indirect_jump (rtx loc)
{
if (! ((*insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate)
(loc, Pmode)))
is not supported. */
rtx
-emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
- unsignedp)
- rtx target;
- enum rtx_code code;
- rtx op0, op1;
- enum machine_mode cmode;
- rtx op2, op3;
- enum machine_mode mode;
- int unsignedp;
+emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
+ enum machine_mode cmode, rtx op2, rtx op3,
+ enum machine_mode mode, int unsignedp)
{
rtx tem, subtarget, comparison, insn;
enum insn_code icode;
/* get_condition will prefer to generate LT and GT even if the old
comparison was against zero, so undo that canonicalization here since
comparisons against zero are cheaper. */
- if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
+ if (code == LT && op1 == const1_rtx)
code = LE, op1 = const0_rtx;
- else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
+ else if (code == GT && op1 == constm1_rtx)
code = GE, op1 = const0_rtx;
if (cmode == VOIDmode)
/* Everything should now be in the suitable form, so emit the compare insn
and then the conditional move. */
- comparison
+ comparison
= compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
/* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */
situation. */
if (GET_CODE (comparison) != code)
return NULL_RTX;
-
+
insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
/* If that failed, then give up. */
comparisons, and vice versa. How do we handle them? */
int
-can_conditionally_move_p (mode)
- enum machine_mode mode;
+can_conditionally_move_p (enum machine_mode mode)
{
if (movcc_gen_code[mode] != CODE_FOR_nothing)
return 1;
is not supported. */
rtx
-emit_conditional_add (target, code, op0, op1, cmode, op2, op3, mode,
- unsignedp)
- rtx target;
- enum rtx_code code;
- rtx op0, op1;
- enum machine_mode cmode;
- rtx op2, op3;
- enum machine_mode mode;
- int unsignedp;
+emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
+ enum machine_mode cmode, rtx op2, rtx op3,
+ enum machine_mode mode, int unsignedp)
{
rtx tem, subtarget, comparison, insn;
enum insn_code icode;
/* get_condition will prefer to generate LT and GT even if the old
comparison was against zero, so undo that canonicalization here since
comparisons against zero are cheaper. */
- if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
+ if (code == LT && op1 == const1_rtx)
code = LE, op1 = const0_rtx;
- else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
+ else if (code == GT && op1 == constm1_rtx)
code = GE, op1 = const0_rtx;
if (cmode == VOIDmode)
/* Everything should now be in the suitable form, so emit the compare insn
and then the conditional move. */
- comparison
+ comparison
= compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
/* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */
situation. */
if (GET_CODE (comparison) != code)
return NULL_RTX;
-
+
insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
/* If that failed, then give up. */
return target;
}
\f
-/* These functions generate an insn body and return it
- rather than emitting the insn.
+/* These functions attempt to generate an insn body, rather than
+ emitting the insn, but if the gen function already emits them, we
+ make no attempt to turn them back into naked patterns.
They do not protect from queued increments,
because they may be used 1) in protect_from_queue itself
/* Generate and return an insn body to add Y to X. */
rtx
-gen_add2_insn (x, y)
- rtx x, y;
+gen_add2_insn (rtx x, rtx y)
{
- int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
+ int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
if (! ((*insn_data[icode].operand[0].predicate)
(x, insn_data[icode].operand[0].mode))
/* Generate and return an insn body to add r1 and c,
storing the result in r0. */
rtx
-gen_add3_insn (r0, r1, c)
- rtx r0, r1, c;
+gen_add3_insn (rtx r0, rtx r1, rtx c)
{
int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
}
int
-have_add2_insn (x, y)
- rtx x, y;
+have_add2_insn (rtx x, rtx y)
{
int icode;
if (GET_MODE (x) == VOIDmode)
abort ();
- icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
+ icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
if (icode == CODE_FOR_nothing)
return 0;
/* Generate and return an insn body to subtract Y from X. */
rtx
-gen_sub2_insn (x, y)
- rtx x, y;
+gen_sub2_insn (rtx x, rtx y)
{
- int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
+ int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
if (! ((*insn_data[icode].operand[0].predicate)
(x, insn_data[icode].operand[0].mode))
/* Generate and return an insn body to subtract r1 and c,
storing the result in r0. */
rtx
-gen_sub3_insn (r0, r1, c)
- rtx r0, r1, c;
+gen_sub3_insn (rtx r0, rtx r1, rtx c)
{
int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
}
int
-have_sub2_insn (x, y)
- rtx x, y;
+have_sub2_insn (rtx x, rtx y)
{
int icode;
if (GET_MODE (x) == VOIDmode)
abort ();
- icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
+ icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
if (icode == CODE_FOR_nothing)
return 0;
It may be a list of insns, if one insn isn't enough. */
rtx
-gen_move_insn (x, y)
- rtx x, y;
+gen_move_insn (rtx x, rtx y)
{
- enum machine_mode mode = GET_MODE (x);
- enum insn_code insn_code;
rtx seq;
- if (mode == VOIDmode)
- mode = GET_MODE (y);
-
- insn_code = mov_optab->handlers[(int) mode].insn_code;
-
- /* Handle MODE_CC modes: If we don't have a special move insn for this mode,
- find a mode to do it in. If we have a movcc, use it. Otherwise,
- find the MODE_INT mode of the same width. */
-
- if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
- {
- enum machine_mode tmode = VOIDmode;
- rtx x1 = x, y1 = y;
-
- if (mode != CCmode
- && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
- tmode = CCmode;
- else
- for (tmode = QImode; tmode != VOIDmode;
- tmode = GET_MODE_WIDER_MODE (tmode))
- if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
- break;
-
- if (tmode == VOIDmode)
- abort ();
-
- /* Get X and Y in TMODE. We can't use gen_lowpart here because it
- may call change_address which is not appropriate if we were
- called when a reload was in progress. We don't have to worry
- about changing the address since the size in bytes is supposed to
- be the same. Copy the MEM to change the mode and move any
- substitutions from the old MEM to the new one. */
-
- if (reload_in_progress)
- {
- x = gen_lowpart_common (tmode, x1);
- if (x == 0 && GET_CODE (x1) == MEM)
- {
- x = adjust_address_nv (x1, tmode, 0);
- copy_replacements (x1, x);
- }
-
- y = gen_lowpart_common (tmode, y1);
- if (y == 0 && GET_CODE (y1) == MEM)
- {
- y = adjust_address_nv (y1, tmode, 0);
- copy_replacements (y1, y);
- }
- }
- else
- {
- x = gen_lowpart (tmode, x);
- y = gen_lowpart (tmode, y);
- }
-
- insn_code = mov_optab->handlers[(int) tmode].insn_code;
- return (GEN_FCN (insn_code) (x, y));
- }
-
start_sequence ();
emit_move_insn_1 (x, y);
seq = get_insns ();
no such operation exists, CODE_FOR_nothing will be returned. */
enum insn_code
-can_extend_p (to_mode, from_mode, unsignedp)
- enum machine_mode to_mode, from_mode;
- int unsignedp;
+can_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
+ int unsignedp)
{
#ifdef HAVE_ptr_extend
if (unsignedp < 0)
into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */
rtx
-gen_extend_insn (x, y, mto, mfrom, unsignedp)
- rtx x, y;
- enum machine_mode mto, mfrom;
- int unsignedp;
+gen_extend_insn (rtx x, rtx y, enum machine_mode mto,
+ enum machine_mode mfrom, int unsignedp)
{
return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y));
}
an explicit FTRUNC insn before the fix insn; otherwise 0. */
static enum insn_code
-can_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
- enum machine_mode fltmode, fixmode;
- int unsignedp;
- int *truncp_ptr;
+can_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
+ int unsignedp, int *truncp_ptr)
{
*truncp_ptr = 0;
if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]
}
static enum insn_code
-can_float_p (fltmode, fixmode, unsignedp)
- enum machine_mode fixmode, fltmode;
- int unsignedp;
+can_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
+ int unsignedp)
{
return floattab[(int) fltmode][(int) fixmode][unsignedp != 0];
}
if it is negative. */
void
-expand_float (to, from, unsignedp)
- rtx to, from;
- int unsignedp;
+expand_float (rtx to, rtx from, int unsignedp)
{
enum insn_code icode;
rtx target = to;
rtx temp1;
rtx neglabel = gen_label_rtx ();
- /* Don't use TARGET if it isn't a register, is a hard register,
+ /* Don't use TARGET if it isn't a register, is a hard register,
or is the wrong mode. */
if (GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
NULL_RTX, 1);
- temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
+ temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
OPTAB_LIB_WIDEN);
expand_float (target, temp, 0);
emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
0, label);
-
+
real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
temp = expand_binop (fmode, add_optab, target,
CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
and store in TO. FROM must be floating point. */
static rtx
-ftruncify (x)
- rtx x;
+ftruncify (rtx x)
{
rtx temp = gen_reg_rtx (GET_MODE (x));
return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
}
void
-expand_fix (to, from, unsignedp)
- rtx to, from;
- int unsignedp;
+expand_fix (rtx to, rtx from, int unsignedp)
{
enum insn_code icode;
rtx target = to;
one plus the highest signed number, convert, and add it back.
We only need to check all real modes, since we know we didn't find
- anything with a wider integer mode.
+ anything with a wider integer mode.
This code used to extend FP value into mode wider than the destination.
This is not needed. Consider, for instance conversion from SFmode
In the other path we know the value is positive in the range 2^63..2^64-1
inclusive. (as for other imput overflow happens and result is undefined)
- So we know that the most important bit set in mantisa corresponds to
+ So we know that the most important bit set in mantissa corresponds to
2^63. The subtraction of 2^63 should not generate any rounding as it
simply clears out that bit. The rest is trivial. */
gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
GET_MODE (to), from));
}
-
+
if (target != to)
{
if (GET_MODE (to) == GET_MODE (target))
/* Report whether we have an instruction to perform the operation
specified by CODE on operands of mode MODE. */
int
-have_insn_for (code, mode)
- enum rtx_code code;
- enum machine_mode mode;
+have_insn_for (enum rtx_code code, enum machine_mode mode)
{
return (code_to_optab[(int) code] != 0
&& (code_to_optab[(int) code]->handlers[(int) mode].insn_code
/* Create a blank optab. */
static optab
-new_optab ()
+new_optab (void)
{
int i;
- optab op = (optab) ggc_alloc (sizeof (struct optab));
+ optab op = ggc_alloc (sizeof (struct optab));
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
op->handlers[i].insn_code = CODE_FOR_nothing;
/* Same, but fill in its code as CODE, and write it into the
code_to_optab table. */
static inline optab
-init_optab (code)
- enum rtx_code code;
+init_optab (enum rtx_code code)
{
optab op = new_optab ();
op->code = code;
/* Same, but fill in its code as CODE, and do _not_ write it into
the code_to_optab table. */
static inline optab
-init_optabv (code)
- enum rtx_code code;
+init_optabv (enum rtx_code code)
{
optab op = new_optab ();
op->code = code;
*/
static void
-init_libfuncs (optable, first_mode, last_mode, opname, suffix)
- optab optable;
- int first_mode;
- int last_mode;
- const char *opname;
- int suffix;
+init_libfuncs (optab optable, int first_mode, int last_mode,
+ const char *opname, int suffix)
{
int mode;
unsigned opname_len = strlen (opname);
*p = '\0';
optable->handlers[(int) mode].libfunc
- = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
- p - libfunc_name));
+ = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
}
}
routine. (See above). */
static void
-init_integral_libfuncs (optable, opname, suffix)
- optab optable;
- const char *opname;
- int suffix;
+init_integral_libfuncs (optab optable, const char *opname, int suffix)
{
+ int maxsize = 2*BITS_PER_WORD;
+ if (maxsize < LONG_LONG_TYPE_SIZE)
+ maxsize = LONG_LONG_TYPE_SIZE;
init_libfuncs (optable, word_mode,
- mode_for_size (2*BITS_PER_WORD, MODE_INT, 0),
+ mode_for_size (maxsize, MODE_INT, 0),
opname, suffix);
}
routine. (See above). */
static void
-init_floating_libfuncs (optable, opname, suffix)
- optab optable;
- const char *opname;
- int suffix;
+init_floating_libfuncs (optab optable, const char *opname, int suffix)
{
enum machine_mode fmode, dmode, lmode;
}
rtx
-init_one_libfunc (name)
- const char *name;
+init_one_libfunc (const char *name)
{
+ rtx symbol;
+
/* Create a FUNCTION_DECL that can be passed to
targetm.encode_section_info. */
/* ??? We don't have any type information except for this is
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
- /* Return the symbol_ref from the mem rtx. */
- return XEXP (DECL_RTL (decl), 0);
+ symbol = XEXP (DECL_RTL (decl), 0);
+
+ /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with
+ are the flags assigned by targetm.encode_section_info. */
+ SYMBOL_REF_DECL (symbol) = 0;
+
+ return symbol;
}
/* Call this once to initialize the contents of the optabs
appropriately for the current target machine. */
void
-init_optabs ()
+init_optabs (void)
{
unsigned int i, j, k;
cos_optab = init_optab (UNKNOWN);
exp_optab = init_optab (UNKNOWN);
log_optab = init_optab (UNKNOWN);
+ tan_optab = init_optab (UNKNOWN);
+ atan_optab = init_optab (UNKNOWN);
strlen_optab = init_optab (UNKNOWN);
cbranch_optab = init_optab (UNKNOWN);
cmov_optab = init_optab (UNKNOWN);
bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
memset_libfunc = init_one_libfunc ("memset");
bzero_libfunc = init_one_libfunc ("bzero");
+ setbits_libfunc = init_one_libfunc ("__setbits");
unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
? "_Unwind_SjLj_Resume"
profile_function_exit_libfunc
= init_one_libfunc ("__cyg_profile_func_exit");
-#ifdef HAVE_conditional_trap
- init_traps ();
-#endif
+ gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
+ gcov_init_libfunc = init_one_libfunc ("__gcov_init");
+
+ if (HAVE_conditional_trap)
+ trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
#ifdef INIT_TARGET_OPTABS
/* Allow the target to add more libcalls or rename some, etc. */
#endif
}
\f
-static GTY(()) rtx trap_rtx;
-
-#ifdef HAVE_conditional_trap
-/* The insn generating function can not take an rtx_code argument.
- TRAP_RTX is used as an rtx argument. Its code is replaced with
- the code to be used in the trap insn and all other fields are
- ignored. */
-
-static void
-init_traps ()
-{
- if (HAVE_conditional_trap)
- {
- trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
- }
-}
-#endif
-
/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
CODE. Return 0 on failure. */
rtx
-gen_cond_trap (code, op1, op2, tcode)
- enum rtx_code code ATTRIBUTE_UNUSED;
- rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
+gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
+ rtx op2 ATTRIBUTE_UNUSED, rtx tcode ATTRIBUTE_UNUSED)
{
enum machine_mode mode = GET_MODE (op1);
+ enum insn_code icode;
+ rtx insn;
+
+ if (!HAVE_conditional_trap)
+ return 0;
if (mode == VOIDmode)
return 0;
-#ifdef HAVE_conditional_trap
- if (HAVE_conditional_trap
- && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ icode = cmp_optab->handlers[(int) mode].insn_code;
+ if (icode == CODE_FOR_nothing)
+ return 0;
+
+ start_sequence ();
+ op1 = prepare_operand (icode, op1, 0, mode, mode, 0);
+ op2 = prepare_operand (icode, op2, 1, mode, mode, 0);
+ if (!op1 || !op2)
{
- rtx insn;
- start_sequence ();
- emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
- PUT_CODE (trap_rtx, code);
- insn = gen_conditional_trap (trap_rtx, tcode);
- if (insn)
- {
- emit_insn (insn);
- insn = get_insns ();
- }
end_sequence ();
- return insn;
+ return 0;
}
-#endif
+ emit_insn (GEN_FCN (icode) (op1, op2));
- return 0;
+ PUT_CODE (trap_rtx, code);
+ insn = gen_conditional_trap (trap_rtx, tcode);
+ if (insn)
+ {
+ emit_insn (insn);
+ insn = get_insns ();
+ }
+ end_sequence ();
+
+ return insn;
}
#include "gt-optabs.h"