summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/optabs.c
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2004-07-28 03:11:36 +0000
committerkan <kan@FreeBSD.org>2004-07-28 03:11:36 +0000
commit5e00ec74d8ce58f99801200d4d3d0412c7cc1b28 (patch)
tree052f4bb635f2bea2c5e350bd60c902be100a0d1e /contrib/gcc/optabs.c
parent87b8398a7d9f9bf0e28bbcd54a4fc27db2125f38 (diff)
downloadFreeBSD-src-5e00ec74d8ce58f99801200d4d3d0412c7cc1b28.zip
FreeBSD-src-5e00ec74d8ce58f99801200d4d3d0412c7cc1b28.tar.gz
Gcc 3.4.2 20040728.
Diffstat (limited to 'contrib/gcc/optabs.c')
-rw-r--r--contrib/gcc/optabs.c2131
1 files changed, 1047 insertions, 1084 deletions
diff --git a/contrib/gcc/optabs.c b/contrib/gcc/optabs.c
index d4eb640..3d85a06 100644
--- a/contrib/gcc/optabs.c
+++ b/contrib/gcc/optabs.c
@@ -1,6 +1,6 @@
/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "toplev.h"
/* Include insn-config.h before expr.h so that HAVE_conditional_move
@@ -41,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "ggc.h"
#include "real.h"
#include "basic-block.h"
+#include "target.h"
/* Each optab contains info on how this target machine
can perform a particular operation
@@ -55,13 +58,8 @@ optab optab_table[OTI_MAX];
rtx libfunc_table[LTI_MAX];
-/* Tables of patterns for extending one integer mode to another. */
-enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
-
-/* Tables of patterns for converting between fixed and floating point. */
-enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
-enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
-enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
+/* Tables of patterns for converting one mode to another. */
+convert_optab convert_optab_table[CTI_MAX];
/* Contains the optab used for each rtx code. */
optab code_to_optab[NUM_RTX_CODE + 1];
@@ -91,41 +89,44 @@ enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
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 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));
-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 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 convert_optab new_convert_optab (void);
+static inline optab init_optab (enum rtx_code);
+static inline optab init_optabv (enum rtx_code);
+static inline convert_optab init_convert_optab (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 init_interclass_conv_libfuncs (convert_optab, const char *,
+ enum mode_class, enum mode_class);
+static void init_intraclass_conv_libfuncs (convert_optab, const char *,
+ enum mode_class, bool);
+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
@@ -143,11 +144,7 @@ static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
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;
@@ -174,11 +171,9 @@ add_equal_note (insns, target, code, op0, op1)
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
@@ -208,16 +203,13 @@ add_equal_note (insns, target, code, op0, op1)
/* 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;
@@ -250,14 +242,10 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
/* 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;
@@ -267,7 +255,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
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;
@@ -308,7 +296,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
/* 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);
@@ -333,7 +321,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
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);
@@ -382,14 +370,10 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
/* 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;
@@ -408,7 +392,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
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);
@@ -646,13 +630,9 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
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)
@@ -673,13 +653,8 @@ expand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
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
@@ -705,8 +680,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
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
@@ -1066,7 +1050,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
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);
}
@@ -1272,7 +1256,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (i > 0)
{
rtx newx;
-
+
/* Add/subtract previous carry to main result. */
newx = expand_binop (word_mode,
normalizep == 1 ? binoptab : otheroptab,
@@ -1300,16 +1284,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
}
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)));
@@ -1327,7 +1312,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* 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:
_______________________
@@ -1481,7 +1466,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
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)
@@ -1500,7 +1485,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
{
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)));
@@ -1536,24 +1521,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
rtx real0 = 0, imag0 = 0;
rtx real1 = 0, imag1 = 0;
rtx realr, imagr, res;
- rtx seq;
- rtx equiv_value;
+ rtx seq, result;
int ok = 0;
- /* Find the correct mode for the real and imaginary parts */
- enum machine_mode submode = GET_MODE_INNER(mode);
+ /* Find the correct mode for the real and imaginary parts. */
+ enum machine_mode submode = GET_MODE_INNER (mode);
if (submode == BLKmode)
abort ();
- if (! target)
- target = gen_reg_rtx (mode);
-
start_sequence ();
- realr = gen_realpart (submode, target);
- imagr = gen_imagpart (submode, target);
-
if (GET_MODE (op0) == mode)
{
real0 = gen_realpart (submode, op0);
@@ -1573,6 +1551,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
abort ();
+ result = gen_reg_rtx (mode);
+ realr = gen_realpart (submode, result);
+ imagr = gen_imagpart (submode, result);
+
switch (binoptab->code)
{
case PLUS:
@@ -1642,8 +1624,13 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
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;
@@ -1691,7 +1678,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
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) */
@@ -1749,7 +1736,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
}
}
break;
-
+
default:
abort ();
}
@@ -1759,16 +1746,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (ok)
{
- if (binoptab->code != UNKNOWN)
- equiv_value
- = gen_rtx_fmt_ee (binoptab->code, mode,
- copy_rtx (op0), copy_rtx (op1));
- else
- equiv_value = 0;
-
- emit_no_conflict_block (seq, target, op0, op1, equiv_value);
-
- return target;
+ rtx equiv = gen_rtx_fmt_ee (binoptab->code, mode,
+ copy_rtx (op0), copy_rtx (op1));
+ emit_no_conflict_block (seq, result, op0, op1, equiv);
+ return result;
}
}
@@ -1891,13 +1872,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* 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;
@@ -2018,12 +1995,8 @@ expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* 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;
@@ -2049,7 +2022,7 @@ expand_vector_unop (mode, unoptab, op0, target, unsignedp)
/* 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);
@@ -2122,12 +2095,9 @@ expand_vector_unop (mode, unoptab, op0, target, unsignedp)
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;
@@ -2184,11 +2154,8 @@ sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
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;
@@ -2269,7 +2236,7 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
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)
{
@@ -2316,12 +2283,8 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
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)
@@ -2330,6 +2293,83 @@ expand_simple_unop (mode, code, op0, target, unsignedp)
return expand_unop (mode, unop, op0, target, unsignedp);
}
+/* Try calculating
+ (clz:narrow x)
+ as
+ (clz:wide (zero_extend:wide x)) - ((width wide) - (width narrow)). */
+static rtx
+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)
+ {
+ enum machine_mode wider_mode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+ {
+ if (clz_optab->handlers[(int) wider_mode].insn_code
+ != CODE_FOR_nothing)
+ {
+ rtx xop0, temp, last;
+
+ last = get_last_insn ();
+
+ if (target == 0)
+ target = gen_reg_rtx (mode);
+ xop0 = widen_operand (op0, wider_mode, mode, true, false);
+ temp = expand_unop (wider_mode, clz_optab, xop0, NULL_RTX, true);
+ if (temp != 0)
+ temp = expand_binop (wider_mode, sub_optab, temp,
+ GEN_INT (GET_MODE_BITSIZE (wider_mode)
+ - GET_MODE_BITSIZE (mode)),
+ target, true, OPTAB_DIRECT);
+ if (temp == 0)
+ delete_insns_since (last);
+
+ return temp;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Try calculating (parity x) as (and (popcount x) 1), where
+ popcount can also be done in a wider mode. */
+static rtx
+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)
+ {
+ enum machine_mode wider_mode;
+ for (wider_mode = mode; wider_mode != VOIDmode;
+ wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+ {
+ if (popcount_optab->handlers[(int) wider_mode].insn_code
+ != CODE_FOR_nothing)
+ {
+ rtx xop0, temp, last;
+
+ last = get_last_insn ();
+
+ if (target == 0)
+ target = gen_reg_rtx (mode);
+ xop0 = widen_operand (op0, wider_mode, mode, true, false);
+ temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX,
+ true);
+ if (temp != 0)
+ temp = expand_binop (wider_mode, and_optab, temp, GEN_INT (1),
+ target, true, OPTAB_DIRECT);
+ if (temp == 0)
+ delete_insns_since (last);
+
+ return temp;
+ }
+ }
+ }
+ return 0;
+}
+
/* Generate code to perform an operation specified by UNOPTAB
on operand OP0, with result having machine-mode MODE.
@@ -2342,12 +2382,8 @@ expand_simple_unop (mode, code, op0, target, unsignedp)
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;
@@ -2401,7 +2437,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
}
emit_insn (pat);
-
+
return temp;
}
else
@@ -2410,6 +2446,16 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
/* It can't be done in this mode. Can we open-code it in a wider mode? */
+ /* Widening clz needs special treatment. */
+ if (unoptab == clz_optab)
+ {
+ temp = widen_clz (mode, op0, target);
+ if (temp)
+ return temp;
+ else
+ goto try_libcall;
+ }
+
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
@@ -2426,7 +2472,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
-
+
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
@@ -2490,7 +2536,7 @@ expand_unop (mode, unoptab, op0, target, 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)
@@ -2498,7 +2544,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
if (target == 0)
target = gen_reg_rtx (mode);
-
+
start_sequence ();
target_piece = gen_imagpart (submode, target);
@@ -2524,22 +2570,90 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
return target;
}
+ /* Try negating floating point values by flipping the sign bit. */
+ if (unoptab->code == NEG && class == MODE_FLOAT
+ && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ const struct real_format *fmt = REAL_MODE_FORMAT (mode);
+ enum machine_mode imode = int_mode_for_mode (mode);
+ int bitpos = (fmt != 0) ? fmt->signbit : -1;
+
+ if (imode != BLKmode && bitpos >= 0 && fmt->has_signed_zero)
+ {
+ HOST_WIDE_INT hi, lo;
+ rtx last = get_last_insn ();
+
+ /* Handle targets with different FP word orders. */
+ if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+ {
+ int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+ int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+ bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+ }
+
+ if (bitpos < HOST_BITS_PER_WIDE_INT)
+ {
+ hi = 0;
+ lo = (HOST_WIDE_INT) 1 << bitpos;
+ }
+ else
+ {
+ hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+ lo = 0;
+ }
+ temp = expand_binop (imode, xor_optab,
+ gen_lowpart (imode, op0),
+ immed_double_const (lo, hi, imode),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ if (temp != 0)
+ {
+ rtx insn;
+ if (target == 0)
+ target = gen_reg_rtx (mode);
+ insn = emit_move_insn (target, gen_lowpart (mode, temp));
+ set_unique_reg_note (insn, REG_EQUAL,
+ gen_rtx_fmt_e (NEG, mode,
+ copy_rtx (op0)));
+ return target;
+ }
+ delete_insns_since (last);
+ }
+ }
+
+ /* Try calculating parity (x) as popcount (x) % 2. */
+ if (unoptab == parity_optab)
+ {
+ temp = expand_parity (mode, op0, target);
+ if (temp)
+ return temp;
+ }
+
+ try_libcall:
/* Now try a library call in this mode. */
if (unoptab->handlers[(int) mode].libfunc)
{
rtx insns;
rtx value;
+ enum machine_mode outmode = mode;
+
+ /* All of these functions return small values. Thus we choose to
+ have them return something that isn't a double-word. */
+ if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab
+ || unoptab == popcount_optab || unoptab == parity_optab)
+ outmode
+ = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node)));
start_sequence ();
/* Pass 1 for NO_QUEUE so we don't lose any increments
if the libcall is cse'd or moved. */
value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
- NULL_RTX, LCT_CONST, mode, 1, op0, mode);
+ NULL_RTX, LCT_CONST, outmode,
+ 1, op0, mode);
insns = get_insns ();
end_sequence ();
- target = gen_reg_rtx (mode);
+ target = gen_reg_rtx (outmode);
emit_libcall_block (insns, target, value,
gen_rtx_fmt_e (unoptab->code, mode, op0));
@@ -2570,10 +2684,18 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
-
+
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
+ /* If we are generating clz using wider mode, adjust the
+ result. */
+ if (unoptab == clz_optab && temp != 0)
+ temp = expand_binop (wider_mode, sub_optab, temp,
+ GEN_INT (GET_MODE_BITSIZE (wider_mode)
+ - GET_MODE_BITSIZE (mode)),
+ target, true, OPTAB_DIRECT);
+
if (temp)
{
if (class != MODE_INT)
@@ -2595,7 +2717,7 @@ expand_unop (mode, unoptab, op0, target, 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,
@@ -2604,7 +2726,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
if (temp)
return temp;
}
-
+
return 0;
}
@@ -2618,14 +2740,10 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
*/
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;
@@ -2636,6 +2754,56 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
if (temp != 0)
return temp;
+ /* For floating point modes, try clearing the sign bit. */
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ const struct real_format *fmt = REAL_MODE_FORMAT (mode);
+ enum machine_mode imode = int_mode_for_mode (mode);
+ int bitpos = (fmt != 0) ? fmt->signbit : -1;
+
+ if (imode != BLKmode && bitpos >= 0)
+ {
+ HOST_WIDE_INT hi, lo;
+ rtx last = get_last_insn ();
+
+ /* Handle targets with different FP word orders. */
+ if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+ {
+ int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+ int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+ bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+ }
+
+ if (bitpos < HOST_BITS_PER_WIDE_INT)
+ {
+ hi = 0;
+ lo = (HOST_WIDE_INT) 1 << bitpos;
+ }
+ else
+ {
+ hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+ lo = 0;
+ }
+ temp = expand_binop (imode, and_optab,
+ gen_lowpart (imode, op0),
+ immed_double_const (~lo, ~hi, imode),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ if (temp != 0)
+ {
+ rtx insn;
+ if (target == 0)
+ target = gen_reg_rtx (mode);
+ insn = emit_move_insn (target, gen_lowpart (mode, temp));
+ set_unique_reg_note (insn, REG_EQUAL,
+ gen_rtx_fmt_e (ABS, mode,
+ copy_rtx (op0)));
+ return target;
+ }
+ delete_insns_since (last);
+ }
+ }
+
/* If we have a MAX insn, we can do this as MAX (x, -x). */
if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
@@ -2672,6 +2840,22 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
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
@@ -2695,7 +2879,7 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
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,
@@ -2720,11 +2904,8 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
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;
@@ -2783,16 +2964,16 @@ expand_complex_abs (mode, op0, target, unsignedp)
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
@@ -2804,7 +2985,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
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;
@@ -2920,11 +3101,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
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;
@@ -2953,7 +3130,7 @@ emit_unop_insn (icode, target, op0, code)
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)
@@ -2974,7 +3151,7 @@ emit_unop_insn (icode, target, op0, code)
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.
@@ -2989,11 +3166,7 @@ emit_unop_insn (icode, target, op0, code)
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;
@@ -3014,7 +3187,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
next = NEXT_INSN (insn);
- /* Some ports (cris) create an libcall regions at their own. We must
+ /* Some ports (cris) create a libcall regions at their own. We must
avoid any potential nesting of LIBCALLs. */
if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
remove_note (insn, note);
@@ -3130,11 +3303,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
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;
@@ -3143,7 +3312,7 @@ emit_libcall_block (insns, target, result, equiv)
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))
@@ -3152,7 +3321,7 @@ emit_libcall_block (insns, target, result, 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);
}
@@ -3166,7 +3335,7 @@ emit_libcall_block (insns, target, result, equiv)
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
@@ -3185,7 +3354,7 @@ emit_libcall_block (insns, target, result, equiv)
rtx set = single_set (insn);
rtx note;
- /* Some ports (cris) create an libcall regions at their own. We must
+ /* Some ports (cris) create a libcall regions at their own. We must
avoid any potential nesting of LIBCALLs. */
if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
remove_note (insn, note);
@@ -3213,6 +3382,11 @@ emit_libcall_block (insns, target, result, equiv)
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 ();
@@ -3277,8 +3451,7 @@ emit_libcall_block (insns, target, result, equiv)
/* 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);
}
@@ -3287,8 +3460,7 @@ emit_clr_insn (x)
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);
}
@@ -3298,14 +3470,12 @@ emit_0_to_1_insn (x)
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
{
@@ -3353,13 +3523,9 @@ can_compare_p (code, mode, purpose)
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;
@@ -3375,8 +3541,17 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
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
@@ -3405,77 +3580,87 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
if (mode == BLKmode)
{
+ enum machine_mode cmp_mode, result_mode;
+ enum insn_code cmp_code;
+ tree length_type;
+ rtx libfunc;
rtx result;
- enum machine_mode result_mode;
- rtx opalign ATTRIBUTE_UNUSED
+ rtx opalign
= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
+ if (size == 0)
+ abort ();
+
emit_queue ();
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
+ size = protect_from_queue (size, 0);
- if (size == 0)
- abort ();
-#ifdef HAVE_cmpstrqi
- if (HAVE_cmpstrqi
- && GET_CODE (size) == CONST_INT
- && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
- {
- result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
- result = gen_reg_rtx (result_mode);
- emit_insn (gen_cmpstrqi (result, x, y, size, opalign));
- }
- else
-#endif
-#ifdef HAVE_cmpstrhi
- if (HAVE_cmpstrhi
- && GET_CODE (size) == CONST_INT
- && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
- {
- result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
- result = gen_reg_rtx (result_mode);
- emit_insn (gen_cmpstrhi (result, x, y, size, opalign));
- }
- else
-#endif
-#ifdef HAVE_cmpstrsi
- if (HAVE_cmpstrsi)
+ /* Try to use a memory block compare insn - either cmpstr
+ or cmpmem will do. */
+ for (cmp_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ cmp_mode != VOIDmode;
+ cmp_mode = GET_MODE_WIDER_MODE (cmp_mode))
{
- result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
+ cmp_code = cmpmem_optab[cmp_mode];
+ if (cmp_code == CODE_FOR_nothing)
+ cmp_code = cmpstr_optab[cmp_mode];
+ if (cmp_code == CODE_FOR_nothing)
+ continue;
+
+ /* Must make sure the size fits the insn's mode. */
+ if ((GET_CODE (size) == CONST_INT
+ && INTVAL (size) >= (1 << GET_MODE_BITSIZE (cmp_mode)))
+ || (GET_MODE_BITSIZE (GET_MODE (size))
+ > GET_MODE_BITSIZE (cmp_mode)))
+ continue;
+
+ result_mode = insn_data[cmp_code].operand[0].mode;
result = gen_reg_rtx (result_mode);
- size = protect_from_queue (size, 0);
- emit_insn (gen_cmpstrsi (result, x, y,
- convert_to_mode (SImode, size, 1),
- opalign));
+ 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;
+ return;
}
- else
-#endif
- {
+
+ /* Otherwise call a library function, memcmp if we've got it,
+ bcmp otherwise. */
#ifdef TARGET_MEM_FUNCTIONS
- result = emit_library_call_value (memcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
- TYPE_MODE (integer_type_node), 3,
- XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype), size,
- TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ libfunc = memcmp_libfunc;
+ length_type = sizetype;
#else
- result = emit_library_call_value (bcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
- TYPE_MODE (integer_type_node), 3,
- XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
- convert_to_mode (TYPE_MODE (integer_type_node),
- size,
- TREE_UNSIGNED (integer_type_node)),
- TYPE_MODE (integer_type_node));
+ libfunc = bcmp_libfunc;
+ length_type = integer_type_node;
#endif
-
- result_mode = TYPE_MODE (integer_type_node);
- }
+ result_mode = TYPE_MODE (integer_type_node);
+ cmp_mode = TYPE_MODE (length_type);
+ size = convert_to_mode (TYPE_MODE (length_type), size,
+ TREE_UNSIGNED (length_type));
+
+ result = emit_library_call_value (libfunc, 0, LCT_PURE_MAKE_BLOCK,
+ result_mode, 3,
+ XEXP (x, 0), Pmode,
+ XEXP (y, 0), Pmode,
+ size, cmp_mode);
*px = result;
*py = const0_rtx;
*pmode = result_mode;
return;
}
+ /* Don't allow operands to the compare to trap, as that can put the
+ compare and branch in different basic blocks. */
+ if (flag_non_call_exceptions)
+ {
+ if (may_trap_p (x))
+ x = force_reg (mode, x);
+ if (may_trap_p (y))
+ y = force_reg (mode, y);
+ }
+
*px = x;
*py = y;
if (can_compare_p (*pcomparison, mode, purpose))
@@ -3518,12 +3703,8 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
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);
@@ -3547,12 +3728,8 @@ prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
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);
@@ -3565,9 +3742,9 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
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))
{
@@ -3631,13 +3808,8 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
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;
@@ -3673,12 +3845,8 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
/* 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);
}
@@ -3687,354 +3855,123 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp)
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;
- rtx x = *px = protect_from_queue (*px, 0);
- rtx y = *py = protect_from_queue (*py, 0);
- enum machine_mode mode = GET_MODE (x);
+ enum rtx_code swapped = swap_condition (comparison);
+ rtx x = protect_from_queue (*px, 0);
+ rtx y = protect_from_queue (*py, 0);
+ enum machine_mode orig_mode = GET_MODE (x);
+ enum machine_mode mode;
+ rtx value, target, insns, equiv;
rtx libfunc = 0;
- rtx result;
-
- if (mode == HFmode)
- switch (comparison)
- {
- case EQ:
- libfunc = eqhf2_libfunc;
- break;
-
- case NE:
- libfunc = nehf2_libfunc;
- break;
-
- case GT:
- libfunc = gthf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LT;
- libfunc = lthf2_libfunc;
- }
- break;
-
- case GE:
- libfunc = gehf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LE;
- libfunc = lehf2_libfunc;
- }
- break;
-
- case LT:
- libfunc = lthf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GT;
- libfunc = gthf2_libfunc;
- }
- break;
-
- case LE:
- libfunc = lehf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GE;
- libfunc = gehf2_libfunc;
- }
- break;
-
- case UNORDERED:
- libfunc = unordhf2_libfunc;
- break;
-
- default:
- break;
- }
- else if (mode == SFmode)
- switch (comparison)
- {
- case EQ:
- libfunc = eqsf2_libfunc;
- break;
-
- case NE:
- libfunc = nesf2_libfunc;
- break;
- case GT:
- libfunc = gtsf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LT;
- libfunc = ltsf2_libfunc;
- }
- break;
-
- case GE:
- libfunc = gesf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LE;
- libfunc = lesf2_libfunc;
- }
- break;
-
- case LT:
- libfunc = ltsf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GT;
- libfunc = gtsf2_libfunc;
- }
- break;
-
- case LE:
- libfunc = lesf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GE;
- libfunc = gesf2_libfunc;
- }
- break;
-
- case UNORDERED:
- libfunc = unordsf2_libfunc;
- break;
-
- default:
- break;
- }
- else if (mode == DFmode)
- switch (comparison)
- {
- case EQ:
- libfunc = eqdf2_libfunc;
- break;
-
- case NE:
- libfunc = nedf2_libfunc;
- break;
-
- case GT:
- libfunc = gtdf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LT;
- libfunc = ltdf2_libfunc;
- }
- break;
-
- case GE:
- libfunc = gedf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LE;
- libfunc = ledf2_libfunc;
- }
- break;
-
- case LT:
- libfunc = ltdf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GT;
- libfunc = gtdf2_libfunc;
- }
- break;
-
- case LE:
- libfunc = ledf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GE;
- libfunc = gedf2_libfunc;
- }
- break;
-
- case UNORDERED:
- libfunc = unorddf2_libfunc;
- break;
-
- default:
- break;
- }
- else if (mode == XFmode)
- switch (comparison)
- {
- case EQ:
- libfunc = eqxf2_libfunc;
- break;
-
- case NE:
- libfunc = nexf2_libfunc;
- break;
-
- case GT:
- libfunc = gtxf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LT;
- libfunc = ltxf2_libfunc;
- }
- break;
-
- case GE:
- libfunc = gexf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LE;
- libfunc = lexf2_libfunc;
- }
- break;
-
- case LT:
- libfunc = ltxf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GT;
- libfunc = gtxf2_libfunc;
- }
- break;
-
- case LE:
- libfunc = lexf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GE;
- libfunc = gexf2_libfunc;
- }
- break;
-
- case UNORDERED:
- libfunc = unordxf2_libfunc;
- break;
-
- default:
- break;
- }
- else if (mode == TFmode)
- switch (comparison)
- {
- case EQ:
- libfunc = eqtf2_libfunc;
- break;
-
- case NE:
- libfunc = netf2_libfunc;
- break;
-
- case GT:
- libfunc = gttf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LT;
- libfunc = lttf2_libfunc;
- }
- break;
-
- case GE:
- libfunc = getf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = LE;
- libfunc = letf2_libfunc;
- }
+ for (mode = orig_mode; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
+ {
+ if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc))
break;
- case LT:
- libfunc = lttf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GT;
- libfunc = gttf2_libfunc;
- }
- break;
+ if ((libfunc = code_to_optab[swapped]->handlers[mode].libfunc))
+ {
+ rtx tmp;
+ tmp = x; x = y; y = tmp;
+ comparison = swapped;
+ break;
+ }
+ }
- case LE:
- libfunc = letf2_libfunc;
- if (libfunc == NULL_RTX)
- {
- tmp = x; x = y; y = tmp;
- *pcomparison = GE;
- libfunc = getf2_libfunc;
- }
- break;
+ if (mode == VOIDmode)
+ abort ();
- case UNORDERED:
- libfunc = unordtf2_libfunc;
- break;
+ if (mode != orig_mode)
+ {
+ x = convert_to_mode (mode, x, 0);
+ y = convert_to_mode (mode, y, 0);
+ }
- default:
- break;
- }
+ /* Attach a REG_EQUAL note describing the semantics of the libcall to
+ the RTL. The allows the RTL optimizers to delete the libcall if the
+ condition can be determined at compile-time. */
+ if (comparison == UNORDERED)
+ {
+ rtx temp = simplify_gen_relational (NE, word_mode, mode, x, x);
+ equiv = simplify_gen_relational (NE, word_mode, mode, y, y);
+ equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
+ temp, const_true_rtx, equiv);
+ }
else
{
- enum machine_mode wider_mode;
-
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
- wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+ equiv = simplify_gen_relational (comparison, word_mode, mode, x, y);
+ if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
{
- if ((cmp_optab->handlers[(int) wider_mode].insn_code
- != CODE_FOR_nothing)
- || (cmp_optab->handlers[(int) wider_mode].libfunc != 0))
+ rtx true_rtx, false_rtx;
+
+ switch (comparison)
{
- x = protect_from_queue (x, 0);
- y = protect_from_queue (y, 0);
- *px = convert_to_mode (wider_mode, x, 0);
- *py = convert_to_mode (wider_mode, y, 0);
- prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
- return;
+ case EQ:
+ true_rtx = const0_rtx;
+ false_rtx = const_true_rtx;
+ break;
+
+ case NE:
+ true_rtx = const_true_rtx;
+ false_rtx = const0_rtx;
+ break;
+
+ case GT:
+ true_rtx = const1_rtx;
+ false_rtx = const0_rtx;
+ break;
+
+ case GE:
+ true_rtx = const0_rtx;
+ false_rtx = constm1_rtx;
+ break;
+
+ case LT:
+ true_rtx = constm1_rtx;
+ false_rtx = const0_rtx;
+ break;
+
+ case LE:
+ true_rtx = const0_rtx;
+ false_rtx = const1_rtx;
+ break;
+
+ default:
+ abort ();
}
+ equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
+ equiv, true_rtx, false_rtx);
}
- abort ();
}
- if (libfunc == 0)
- abort ();
+ start_sequence ();
+ value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+ word_mode, 2, x, mode, y, mode);
+ insns = get_insns ();
+ end_sequence ();
- result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
- word_mode, 2, x, mode, y, mode);
- *px = result;
+ target = gen_reg_rtx (word_mode);
+ emit_libcall_block (insns, target, value, equiv);
+
+
+ if (comparison == UNORDERED
+ || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
+ comparison = NE;
+
+ *px = target;
*py = const0_rtx;
*pmode = word_mode;
- if (comparison == UNORDERED)
- *pcomparison = NE;
-#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
- else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
- *pcomparison = NE;
-#endif
+ *pcomparison = comparison;
*punsignedp = 0;
}
/* 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)))
@@ -4061,15 +3998,9 @@ emit_indirect_jump (loc)
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;
@@ -4089,9 +4020,9 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
/* 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)
@@ -4150,7 +4081,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
/* 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)? */
@@ -4159,7 +4090,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
situation. */
if (GET_CODE (comparison) != code)
return NULL_RTX;
-
+
insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
/* If that failed, then give up. */
@@ -4183,8 +4114,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
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;
@@ -4193,9 +4123,132 @@ can_conditionally_move_p (mode)
}
#endif /* HAVE_conditional_move */
+
+/* Emit a conditional addition instruction if the machine supports one for that
+ condition and machine mode.
+
+ OP0 and OP1 are the operands that should be compared using CODE. CMODE is
+ the mode to use should they be constants. If it is VOIDmode, they cannot
+ both be constants.
+
+ OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3
+ should be stored there. MODE is the mode to use should they be constants.
+ If it is VOIDmode, they cannot both be constants.
+
+ The result is either TARGET (perhaps modified) or NULL_RTX if the operation
+ is not supported. */
+
+rtx
+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;
+ enum rtx_code reversed;
+
+ /* If one operand is constant, make it the second one. Only do this
+ if the other operand is not constant as well. */
+
+ if (swap_commutative_operands_p (op0, op1))
+ {
+ tem = op0;
+ op0 = op1;
+ op1 = tem;
+ code = swap_condition (code);
+ }
+
+ /* 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 && op1 == const1_rtx)
+ code = LE, op1 = const0_rtx;
+ else if (code == GT && op1 == constm1_rtx)
+ code = GE, op1 = const0_rtx;
+
+ if (cmode == VOIDmode)
+ cmode = GET_MODE (op0);
+
+ if (swap_commutative_operands_p (op2, op3)
+ && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
+ != UNKNOWN))
+ {
+ tem = op2;
+ op2 = op3;
+ op3 = tem;
+ code = reversed;
+ }
+
+ if (mode == VOIDmode)
+ mode = GET_MODE (op2);
+
+ icode = addcc_optab->handlers[(int) mode].insn_code;
+
+ if (icode == CODE_FOR_nothing)
+ return 0;
+
+ if (flag_force_mem)
+ {
+ op2 = force_not_mem (op2);
+ op3 = force_not_mem (op3);
+ }
+
+ if (target)
+ target = protect_from_queue (target, 1);
+ else
+ target = gen_reg_rtx (mode);
+
+ subtarget = target;
+
+ emit_queue ();
+
+ op2 = protect_from_queue (op2, 0);
+ op3 = protect_from_queue (op3, 0);
+
+ /* If the insn doesn't accept these operands, put them in pseudos. */
+
+ if (! (*insn_data[icode].operand[0].predicate)
+ (subtarget, insn_data[icode].operand[0].mode))
+ subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
+
+ if (! (*insn_data[icode].operand[2].predicate)
+ (op2, insn_data[icode].operand[2].mode))
+ op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
+
+ if (! (*insn_data[icode].operand[3].predicate)
+ (op3, insn_data[icode].operand[3].mode))
+ op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
+
+ /* Everything should now be in the suitable form, so emit the compare insn
+ and then the conditional move. */
+
+ comparison
+ = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
+
+ /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)? */
+ /* We can get const0_rtx or const_true_rtx in some circumstances. Just
+ return NULL and let the caller figure out how best to deal with this
+ situation. */
+ if (GET_CODE (comparison) != code)
+ return NULL_RTX;
+
+ insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+
+ /* If that failed, then give up. */
+ if (insn == 0)
+ return 0;
+
+ emit_insn (insn);
+
+ if (subtarget != target)
+ convert_move (target, subtarget, 0);
+
+ return target;
+}
-/* 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
@@ -4204,10 +4257,9 @@ can_conditionally_move_p (mode)
/* 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))
@@ -4223,8 +4275,7 @@ gen_add2_insn (x, y)
/* 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;
@@ -4241,15 +4292,14 @@ gen_add3_insn (r0, r1, c)
}
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;
@@ -4268,10 +4318,9 @@ have_add2_insn (x, y)
/* 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))
@@ -4287,8 +4336,7 @@ gen_sub2_insn (x, y)
/* 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;
@@ -4305,15 +4353,14 @@ gen_sub3_insn (r0, r1, c)
}
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;
@@ -4333,72 +4380,10 @@ have_sub2_insn (x, y)
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 ();
@@ -4411,28 +4396,28 @@ gen_move_insn (x, y)
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)
{
+ convert_optab tab;
#ifdef HAVE_ptr_extend
if (unsignedp < 0)
return CODE_FOR_ptr_extend;
- else
#endif
- return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0];
+
+ tab = unsignedp ? zext_optab : sext_optab;
+ return tab->handlers[to_mode][from_mode].insn_code;
}
/* Generate the body of an insn to extend Y (with mode MFROM)
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));
+ enum insn_code icode = can_extend_p (mto, mfrom, unsignedp);
+ return GEN_FCN (icode) (x, y);
}
/* can_fix_p and can_float_p say whether the target machine
@@ -4445,30 +4430,41 @@ gen_extend_insn (x, y, mto, mfrom, unsignedp)
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]
- != CODE_FOR_nothing)
- return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0];
+ convert_optab tab;
+ enum insn_code icode;
+
+ tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
+ icode = tab->handlers[fixmode][fltmode].insn_code;
+ if (icode != CODE_FOR_nothing)
+ {
+ *truncp_ptr = 0;
+ return icode;
+ }
- if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
+ tab = unsignedp ? ufix_optab : sfix_optab;
+ icode = tab->handlers[fixmode][fltmode].insn_code;
+ if (icode != CODE_FOR_nothing
+ && ftrunc_optab->handlers[fltmode].insn_code != CODE_FOR_nothing)
{
*truncp_ptr = 1;
- return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0];
+ return icode;
}
+
+ *truncp_ptr = 0;
return CODE_FOR_nothing;
}
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];
+ convert_optab tab;
+
+ tab = unsignedp ? ufloat_optab : sfloat_optab;
+ return tab->handlers[fltmode][fixmode].insn_code;
}
/* Generate code to convert FROM to floating point
@@ -4478,9 +4474,7 @@ can_float_p (fltmode, fixmode, unsignedp)
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;
@@ -4568,7 +4562,7 @@ expand_float (to, from, unsignedp)
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
@@ -4597,7 +4591,7 @@ expand_float (to, from, unsignedp)
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);
@@ -4630,7 +4624,7 @@ expand_float (to, from, unsignedp)
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),
@@ -4643,12 +4637,12 @@ expand_float (to, from, unsignedp)
goto done;
}
- /* No hardware instruction available; call a library routine to convert from
- SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode. */
+ /* No hardware instruction available; call a library routine. */
{
- rtx libfcn;
+ rtx libfunc;
rtx insns;
rtx value;
+ convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
@@ -4659,56 +4653,13 @@ expand_float (to, from, unsignedp)
if (flag_force_mem)
from = force_not_mem (from);
- if (GET_MODE (to) == SFmode)
- {
- if (GET_MODE (from) == SImode)
- libfcn = floatsisf_libfunc;
- else if (GET_MODE (from) == DImode)
- libfcn = floatdisf_libfunc;
- else if (GET_MODE (from) == TImode)
- libfcn = floattisf_libfunc;
- else
- abort ();
- }
- else if (GET_MODE (to) == DFmode)
- {
- if (GET_MODE (from) == SImode)
- libfcn = floatsidf_libfunc;
- else if (GET_MODE (from) == DImode)
- libfcn = floatdidf_libfunc;
- else if (GET_MODE (from) == TImode)
- libfcn = floattidf_libfunc;
- else
- abort ();
- }
- else if (GET_MODE (to) == XFmode)
- {
- if (GET_MODE (from) == SImode)
- libfcn = floatsixf_libfunc;
- else if (GET_MODE (from) == DImode)
- libfcn = floatdixf_libfunc;
- else if (GET_MODE (from) == TImode)
- libfcn = floattixf_libfunc;
- else
- abort ();
- }
- else if (GET_MODE (to) == TFmode)
- {
- if (GET_MODE (from) == SImode)
- libfcn = floatsitf_libfunc;
- else if (GET_MODE (from) == DImode)
- libfcn = floatditf_libfunc;
- else if (GET_MODE (from) == TImode)
- libfcn = floattitf_libfunc;
- else
- abort ();
- }
- else
+ libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
+ if (!libfunc)
abort ();
start_sequence ();
- value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
+ value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
GET_MODE (to), 1, from,
GET_MODE (from));
insns = get_insns ();
@@ -4736,23 +4687,19 @@ expand_float (to, from, unsignedp)
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;
enum machine_mode fmode, imode;
int must_trunc = 0;
- rtx libfcn = 0;
/* We first try to find a pair of modes, one real and one integer, at
least as wide as FROM and TO, respectively, in which we can open-code
@@ -4799,15 +4746,26 @@ expand_fix (to, from, unsignedp)
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
+ into DImode.
+
+ The hot path trought the code is dealing with inputs smaller than 2^63
+ and doing just the conversion, so there is no bits to lose.
+
+ 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 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. */
if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
for (fmode = GET_MODE (from); fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
- /* Make sure we won't lose significant bits doing this. */
- if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
- && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
- &must_trunc))
+ if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
+ &must_trunc))
{
int bitsize;
REAL_VALUE_TYPE offset;
@@ -4882,57 +4840,16 @@ expand_fix (to, from, unsignedp)
expand_fix (target, from, unsignedp);
}
- else if (GET_MODE (from) == SFmode)
- {
- if (GET_MODE (to) == SImode)
- libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc;
- else if (GET_MODE (to) == DImode)
- libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc;
- else if (GET_MODE (to) == TImode)
- libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc;
- else
- abort ();
- }
- else if (GET_MODE (from) == DFmode)
- {
- if (GET_MODE (to) == SImode)
- libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc;
- else if (GET_MODE (to) == DImode)
- libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc;
- else if (GET_MODE (to) == TImode)
- libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc;
- else
- abort ();
- }
- else if (GET_MODE (from) == XFmode)
- {
- if (GET_MODE (to) == SImode)
- libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc;
- else if (GET_MODE (to) == DImode)
- libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc;
- else if (GET_MODE (to) == TImode)
- libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc;
- else
- abort ();
- }
- else if (GET_MODE (from) == TFmode)
- {
- if (GET_MODE (to) == SImode)
- libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc;
- else if (GET_MODE (to) == DImode)
- libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc;
- else if (GET_MODE (to) == TImode)
- libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc;
- else
- abort ();
- }
else
- abort ();
-
- if (libfcn)
{
rtx insns;
rtx value;
+ rtx libfunc;
+
+ convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
+ libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
+ if (!libfunc)
+ abort ();
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
@@ -4942,7 +4859,7 @@ expand_fix (to, from, unsignedp)
start_sequence ();
- value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
+ value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
GET_MODE (to), 1, from,
GET_MODE (from));
insns = get_insns ();
@@ -4952,7 +4869,7 @@ expand_fix (to, from, unsignedp)
gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
GET_MODE (to), from));
}
-
+
if (target != to)
{
if (GET_MODE (to) == GET_MODE (target))
@@ -4965,9 +4882,7 @@ expand_fix (to, from, unsignedp)
/* 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
@@ -4976,10 +4891,10 @@ have_insn_for (code, mode)
/* 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;
@@ -4989,11 +4904,24 @@ new_optab ()
return op;
}
+static convert_optab
+new_convert_optab (void)
+{
+ int i, j;
+ convert_optab op = ggc_alloc (sizeof (struct convert_optab));
+ for (i = 0; i < NUM_MACHINE_MODES; i++)
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ {
+ op->handlers[i][j].insn_code = CODE_FOR_nothing;
+ op->handlers[i][j].libfunc = 0;
+ }
+ return op;
+}
+
/* 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;
@@ -5004,18 +4932,26 @@ init_optab (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;
return op;
}
+/* Conversion optabs never go in the code_to_optab table. */
+static inline convert_optab
+init_convert_optab (enum rtx_code code)
+{
+ convert_optab op = new_convert_optab ();
+ op->code = code;
+ return op;
+}
+
/* Initialize the libfunc fields of an entire group of entries in some
optab. Each entry is set equal to a string consisting of a leading
pair of underscores followed by a generic operation name followed by
- a mode name (downshifted to lower case) followed by a single character
+ a mode name (downshifted to lowercase) followed by a single character
representing the number of operands for the given operation (which is
usually one of the characters '2', '3', or '4').
@@ -5030,12 +4966,8 @@ init_optabv (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);
@@ -5060,8 +4992,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
*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));
}
}
@@ -5071,12 +5002,14 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
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)
{
- init_libfuncs (optable, SImode, TImode, opname, 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 (maxsize, MODE_INT, 0),
+ opname, suffix);
}
/* Initialize the libfunc fields of an entire group of entries in some
@@ -5085,18 +5018,129 @@ init_integral_libfuncs (optable, 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)
+{
+ init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix);
+}
+
+/* Initialize the libfunc fields of an entire group of entries of an
+ inter-mode-class conversion optab. The string formation rules are
+ similar to the ones for init_libfuncs, above, but instead of having
+ a mode name and an operand count these functions have two mode names
+ and no operand count. */
+static void
+init_interclass_conv_libfuncs (convert_optab tab, const char *opname,
+ enum mode_class from_class,
+ enum mode_class to_class)
+{
+ enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);
+ enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);
+ size_t opname_len = strlen (opname);
+ size_t max_mname_len = 0;
+
+ enum machine_mode fmode, tmode;
+ const char *fname, *tname;
+ const char *q;
+ char *libfunc_name, *suffix;
+ char *p;
+
+ for (fmode = first_from_mode;
+ fmode != VOIDmode;
+ fmode = GET_MODE_WIDER_MODE (fmode))
+ max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));
+
+ for (tmode = first_to_mode;
+ tmode != VOIDmode;
+ tmode = GET_MODE_WIDER_MODE (tmode))
+ max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
+
+ libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+ libfunc_name[0] = '_';
+ libfunc_name[1] = '_';
+ memcpy (&libfunc_name[2], opname, opname_len);
+ suffix = libfunc_name + opname_len + 2;
+
+ for (fmode = first_from_mode; fmode != VOIDmode;
+ fmode = GET_MODE_WIDER_MODE (fmode))
+ for (tmode = first_to_mode; tmode != VOIDmode;
+ tmode = GET_MODE_WIDER_MODE (tmode))
+ {
+ fname = GET_MODE_NAME (fmode);
+ tname = GET_MODE_NAME (tmode);
+
+ p = suffix;
+ for (q = fname; *q; p++, q++)
+ *p = TOLOWER (*q);
+ for (q = tname; *q; p++, q++)
+ *p = TOLOWER (*q);
+
+ *p = '\0';
+
+ tab->handlers[tmode][fmode].libfunc
+ = init_one_libfunc (ggc_alloc_string (libfunc_name,
+ p - libfunc_name));
+ }
+}
+
+/* Initialize the libfunc fields of an entire group of entries of an
+ intra-mode-class conversion optab. The string formation rules are
+ similar to the ones for init_libfunc, above. WIDENING says whether
+ the optab goes from narrow to wide modes or vice versa. These functions
+ have two mode names _and_ an operand count. */
+static void
+init_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
+ enum mode_class class, bool widening)
{
- init_libfuncs (optable, SFmode, TFmode, opname, suffix);
+ enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
+ size_t opname_len = strlen (opname);
+ size_t max_mname_len = 0;
+
+ enum machine_mode nmode, wmode;
+ const char *nname, *wname;
+ const char *q;
+ char *libfunc_name, *suffix;
+ char *p;
+
+ for (nmode = first_mode; nmode != VOIDmode;
+ nmode = GET_MODE_WIDER_MODE (nmode))
+ max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
+
+ libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+ libfunc_name[0] = '_';
+ libfunc_name[1] = '_';
+ memcpy (&libfunc_name[2], opname, opname_len);
+ suffix = libfunc_name + opname_len + 2;
+
+ for (nmode = first_mode; nmode != VOIDmode;
+ nmode = GET_MODE_WIDER_MODE (nmode))
+ for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;
+ wmode = GET_MODE_WIDER_MODE (wmode))
+ {
+ nname = GET_MODE_NAME (nmode);
+ wname = GET_MODE_NAME (wmode);
+
+ p = suffix;
+ for (q = widening ? nname : wname; *q; p++, q++)
+ *p = TOLOWER (*q);
+ for (q = widening ? wname : nname; *q; p++, q++)
+ *p = TOLOWER (*q);
+
+ *p++ = '2';
+ *p = '\0';
+
+ tab->handlers[widening ? wmode : nmode]
+ [widening ? nmode : wmode].libfunc
+ = init_one_libfunc (ggc_alloc_string (libfunc_name,
+ p - libfunc_name));
+ }
}
+
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
@@ -5107,40 +5151,49 @@ init_one_libfunc (name)
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 to reset the function entry for one optab (OPTABLE) in mode
+ MODE to NAME, which should be either 0 or a string constant. */
+void
+set_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
+{
+ if (name)
+ optable->handlers[mode].libfunc = init_one_libfunc (name);
+ else
+ optable->handlers[mode].libfunc = 0;
+}
+
+/* Call this to reset the function entry for one conversion optab
+ (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be
+ either 0 or a string constant. */
+void
+set_conv_libfunc (convert_optab optable, enum machine_mode tmode,
+ enum machine_mode fmode, const char *name)
+{
+ if (name)
+ optable->handlers[tmode][fmode].libfunc = init_one_libfunc (name);
+ else
+ optable->handlers[tmode][fmode].libfunc = 0;
}
/* 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;
+ unsigned int i;
/* Start by initializing all tables to contain CODE_FOR_nothing. */
- for (i = 0; i < ARRAY_SIZE (fixtab); i++)
- for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++)
- for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++)
- fixtab[i][j][k] = CODE_FOR_nothing;
-
- for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++)
- for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++)
- for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++)
- fixtrunctab[i][j][k] = CODE_FOR_nothing;
-
- for (i = 0; i < ARRAY_SIZE (floattab); i++)
- for (j = 0; j < ARRAY_SIZE (floattab[0]); j++)
- for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++)
- floattab[i][j][k] = CODE_FOR_nothing;
-
- for (i = 0; i < ARRAY_SIZE (extendtab); i++)
- for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++)
- for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++)
- extendtab[i][j][k] = CODE_FOR_nothing;
-
for (i = 0; i < NUM_RTX_CODE; i++)
setcc_gen_code[i] = CODE_FOR_nothing;
@@ -5179,6 +5232,8 @@ init_optabs ()
smax_optab = init_optab (SMAX);
umin_optab = init_optab (UMIN);
umax_optab = init_optab (UMAX);
+ pow_optab = init_optab (UNKNOWN);
+ atan2_optab = init_optab (UNKNOWN);
/* These three have codes assigned exclusively for the sake of
have_insn_for. */
@@ -5188,27 +5243,64 @@ init_optabs ()
ucmp_optab = init_optab (UNKNOWN);
tst_optab = init_optab (UNKNOWN);
+
+ eq_optab = init_optab (EQ);
+ ne_optab = init_optab (NE);
+ gt_optab = init_optab (GT);
+ ge_optab = init_optab (GE);
+ lt_optab = init_optab (LT);
+ le_optab = init_optab (LE);
+ unord_optab = init_optab (UNORDERED);
+
neg_optab = init_optab (NEG);
negv_optab = init_optabv (NEG);
abs_optab = init_optab (ABS);
absv_optab = init_optabv (ABS);
+ addcc_optab = init_optab (UNKNOWN);
one_cmpl_optab = init_optab (NOT);
ffs_optab = init_optab (FFS);
+ clz_optab = init_optab (CLZ);
+ ctz_optab = init_optab (CTZ);
+ popcount_optab = init_optab (POPCOUNT);
+ parity_optab = init_optab (PARITY);
sqrt_optab = init_optab (SQRT);
+ floor_optab = init_optab (UNKNOWN);
+ ceil_optab = init_optab (UNKNOWN);
+ round_optab = init_optab (UNKNOWN);
+ btrunc_optab = init_optab (UNKNOWN);
+ nearbyint_optab = init_optab (UNKNOWN);
sin_optab = init_optab (UNKNOWN);
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);
cstore_optab = init_optab (UNKNOWN);
push_optab = init_optab (UNKNOWN);
+ vec_extract_optab = init_optab (UNKNOWN);
+ vec_set_optab = init_optab (UNKNOWN);
+ vec_init_optab = init_optab (UNKNOWN);
+ /* Conversions. */
+ sext_optab = init_convert_optab (SIGN_EXTEND);
+ zext_optab = init_convert_optab (ZERO_EXTEND);
+ trunc_optab = init_convert_optab (TRUNCATE);
+ sfix_optab = init_convert_optab (FIX);
+ ufix_optab = init_convert_optab (UNSIGNED_FIX);
+ sfixtrunc_optab = init_convert_optab (UNKNOWN);
+ ufixtrunc_optab = init_convert_optab (UNKNOWN);
+ sfloat_optab = init_convert_optab (FLOAT);
+ ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
+
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
movstr_optab[i] = CODE_FOR_nothing;
clrstr_optab[i] = CODE_FOR_nothing;
+ cmpstr_optab[i] = CODE_FOR_nothing;
+ cmpmem_optab[i] = CODE_FOR_nothing;
#ifdef HAVE_SECONDARY_RELOADS
reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
@@ -5218,14 +5310,6 @@ init_optabs ()
/* Fill in the optabs with the insns we support. */
init_all_optabs ();
-#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
- /* This flag says the same insns that convert to a signed fixnum
- also convert validly to an unsigned one. */
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
-#endif
-
/* Initialize the optabs with the names of the library functions. */
init_integral_libfuncs (add_optab, "add", '3');
init_floating_libfuncs (add_optab, "add", '3');
@@ -5266,78 +5350,44 @@ init_optabs ()
init_floating_libfuncs (negv_optab, "neg", '2');
init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
init_integral_libfuncs (ffs_optab, "ffs", '2');
+ init_integral_libfuncs (clz_optab, "clz", '2');
+ init_integral_libfuncs (ctz_optab, "ctz", '2');
+ init_integral_libfuncs (popcount_optab, "popcount", '2');
+ init_integral_libfuncs (parity_optab, "parity", '2');
/* Comparison libcalls for integers MUST come in pairs, signed/unsigned. */
init_integral_libfuncs (cmp_optab, "cmp", '2');
init_integral_libfuncs (ucmp_optab, "ucmp", '2');
init_floating_libfuncs (cmp_optab, "cmp", '2');
-#ifdef MULSI3_LIBCALL
- smul_optab->handlers[(int) SImode].libfunc
- = init_one_libfunc (MULSI3_LIBCALL);
-#endif
-#ifdef MULDI3_LIBCALL
- smul_optab->handlers[(int) DImode].libfunc
- = init_one_libfunc (MULDI3_LIBCALL);
-#endif
-
-#ifdef DIVSI3_LIBCALL
- sdiv_optab->handlers[(int) SImode].libfunc
- = init_one_libfunc (DIVSI3_LIBCALL);
-#endif
-#ifdef DIVDI3_LIBCALL
- sdiv_optab->handlers[(int) DImode].libfunc
- = init_one_libfunc (DIVDI3_LIBCALL);
-#endif
-
-#ifdef UDIVSI3_LIBCALL
- udiv_optab->handlers[(int) SImode].libfunc
- = init_one_libfunc (UDIVSI3_LIBCALL);
-#endif
-#ifdef UDIVDI3_LIBCALL
- udiv_optab->handlers[(int) DImode].libfunc
- = init_one_libfunc (UDIVDI3_LIBCALL);
-#endif
-
-#ifdef MODSI3_LIBCALL
- smod_optab->handlers[(int) SImode].libfunc
- = init_one_libfunc (MODSI3_LIBCALL);
-#endif
-#ifdef MODDI3_LIBCALL
- smod_optab->handlers[(int) DImode].libfunc
- = init_one_libfunc (MODDI3_LIBCALL);
-#endif
-
-#ifdef UMODSI3_LIBCALL
- umod_optab->handlers[(int) SImode].libfunc
- = init_one_libfunc (UMODSI3_LIBCALL);
-#endif
-#ifdef UMODDI3_LIBCALL
- umod_optab->handlers[(int) DImode].libfunc
- = init_one_libfunc (UMODDI3_LIBCALL);
-#endif
-
- /* Use cabs for DC complex abs, since systems generally have cabs.
- Don't define any libcall for SCmode, so that cabs will be used. */
- abs_optab->handlers[(int) DCmode].libfunc
- = init_one_libfunc ("cabs");
+ /* EQ etc are floating point only. */
+ init_floating_libfuncs (eq_optab, "eq", '2');
+ init_floating_libfuncs (ne_optab, "ne", '2');
+ init_floating_libfuncs (gt_optab, "gt", '2');
+ init_floating_libfuncs (ge_optab, "ge", '2');
+ init_floating_libfuncs (lt_optab, "lt", '2');
+ init_floating_libfuncs (le_optab, "le", '2');
+ init_floating_libfuncs (unord_optab, "unord", '2');
+
+ /* Conversions. */
+ init_interclass_conv_libfuncs (sfloat_optab, "float", MODE_INT, MODE_FLOAT);
+ init_interclass_conv_libfuncs (sfix_optab, "fix", MODE_FLOAT, MODE_INT);
+ init_interclass_conv_libfuncs (ufix_optab, "fixuns", MODE_FLOAT, MODE_INT);
+
+ /* sext_optab is also used for FLOAT_EXTEND. */
+ init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
+ init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);
+
+ /* Use cabs for double complex abs, since systems generally have cabs.
+ Don't define any libcall for float complex, so that cabs will be used. */
+ if (complex_double_type_node)
+ abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc
+ = init_one_libfunc ("cabs");
/* The ffs function operates on `int'. */
ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
= init_one_libfunc ("ffs");
- extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2");
- extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2");
- extendsftf2_libfunc = init_one_libfunc ("__extendsftf2");
- extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2");
- extenddftf2_libfunc = init_one_libfunc ("__extenddftf2");
-
- truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2");
- truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2");
- trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2");
- truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
- trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
-
abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
memmove_libfunc = init_one_libfunc ("memmove");
@@ -5346,6 +5396,7 @@ init_optabs ()
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"
@@ -5361,116 +5412,28 @@ init_optabs ()
unwind_sjlj_unregister_libfunc
= init_one_libfunc ("_Unwind_SjLj_Unregister");
- eqhf2_libfunc = init_one_libfunc ("__eqhf2");
- nehf2_libfunc = init_one_libfunc ("__nehf2");
- gthf2_libfunc = init_one_libfunc ("__gthf2");
- gehf2_libfunc = init_one_libfunc ("__gehf2");
- lthf2_libfunc = init_one_libfunc ("__lthf2");
- lehf2_libfunc = init_one_libfunc ("__lehf2");
- unordhf2_libfunc = init_one_libfunc ("__unordhf2");
-
- eqsf2_libfunc = init_one_libfunc ("__eqsf2");
- nesf2_libfunc = init_one_libfunc ("__nesf2");
- gtsf2_libfunc = init_one_libfunc ("__gtsf2");
- gesf2_libfunc = init_one_libfunc ("__gesf2");
- ltsf2_libfunc = init_one_libfunc ("__ltsf2");
- lesf2_libfunc = init_one_libfunc ("__lesf2");
- unordsf2_libfunc = init_one_libfunc ("__unordsf2");
-
- eqdf2_libfunc = init_one_libfunc ("__eqdf2");
- nedf2_libfunc = init_one_libfunc ("__nedf2");
- gtdf2_libfunc = init_one_libfunc ("__gtdf2");
- gedf2_libfunc = init_one_libfunc ("__gedf2");
- ltdf2_libfunc = init_one_libfunc ("__ltdf2");
- ledf2_libfunc = init_one_libfunc ("__ledf2");
- unorddf2_libfunc = init_one_libfunc ("__unorddf2");
-
- eqxf2_libfunc = init_one_libfunc ("__eqxf2");
- nexf2_libfunc = init_one_libfunc ("__nexf2");
- gtxf2_libfunc = init_one_libfunc ("__gtxf2");
- gexf2_libfunc = init_one_libfunc ("__gexf2");
- ltxf2_libfunc = init_one_libfunc ("__ltxf2");
- lexf2_libfunc = init_one_libfunc ("__lexf2");
- unordxf2_libfunc = init_one_libfunc ("__unordxf2");
-
- eqtf2_libfunc = init_one_libfunc ("__eqtf2");
- netf2_libfunc = init_one_libfunc ("__netf2");
- gttf2_libfunc = init_one_libfunc ("__gttf2");
- getf2_libfunc = init_one_libfunc ("__getf2");
- lttf2_libfunc = init_one_libfunc ("__lttf2");
- letf2_libfunc = init_one_libfunc ("__letf2");
- unordtf2_libfunc = init_one_libfunc ("__unordtf2");
-
- floatsisf_libfunc = init_one_libfunc ("__floatsisf");
- floatdisf_libfunc = init_one_libfunc ("__floatdisf");
- floattisf_libfunc = init_one_libfunc ("__floattisf");
-
- floatsidf_libfunc = init_one_libfunc ("__floatsidf");
- floatdidf_libfunc = init_one_libfunc ("__floatdidf");
- floattidf_libfunc = init_one_libfunc ("__floattidf");
-
- floatsixf_libfunc = init_one_libfunc ("__floatsixf");
- floatdixf_libfunc = init_one_libfunc ("__floatdixf");
- floattixf_libfunc = init_one_libfunc ("__floattixf");
-
- floatsitf_libfunc = init_one_libfunc ("__floatsitf");
- floatditf_libfunc = init_one_libfunc ("__floatditf");
- floattitf_libfunc = init_one_libfunc ("__floattitf");
-
- fixsfsi_libfunc = init_one_libfunc ("__fixsfsi");
- fixsfdi_libfunc = init_one_libfunc ("__fixsfdi");
- fixsfti_libfunc = init_one_libfunc ("__fixsfti");
-
- fixdfsi_libfunc = init_one_libfunc ("__fixdfsi");
- fixdfdi_libfunc = init_one_libfunc ("__fixdfdi");
- fixdfti_libfunc = init_one_libfunc ("__fixdfti");
-
- fixxfsi_libfunc = init_one_libfunc ("__fixxfsi");
- fixxfdi_libfunc = init_one_libfunc ("__fixxfdi");
- fixxfti_libfunc = init_one_libfunc ("__fixxfti");
-
- fixtfsi_libfunc = init_one_libfunc ("__fixtfsi");
- fixtfdi_libfunc = init_one_libfunc ("__fixtfdi");
- fixtfti_libfunc = init_one_libfunc ("__fixtfti");
-
- fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi");
- fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi");
- fixunssfti_libfunc = init_one_libfunc ("__fixunssfti");
-
- fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi");
- fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi");
- fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti");
-
- fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi");
- fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi");
- fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti");
-
- fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi");
- fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi");
- fixunstfti_libfunc = init_one_libfunc ("__fixunstfti");
-
/* For function entry/exit instrumentation. */
profile_function_entry_libfunc
= init_one_libfunc ("__cyg_profile_func_enter");
profile_function_exit_libfunc
= init_one_libfunc ("__cyg_profile_func_exit");
+ 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. */
- INIT_TARGET_OPTABS;
-#endif
+ targetm.init_libfuncs ();
}
/* 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;
OpenPOWER on IntegriCloud