Split up optabs.[hc]

optabs.[hc] is a bit of a behemoth.  It includes basic functions for querying
what a target can do, related tree- and gimple-level query functions,
related rtl-level query functions, and the functions that actually
generate code.  Some gimple optimisations therefore need:

#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"

purely to query whether the target has support for a particular operation.

This patch splits optabs up as follows:

      - optabs-query.[hc]: IL-independent functions for querying what a target
          can do natively.
      - optabs-tree.[hc]: tree and gimple query functions (an extension of
          optabs-query.[hc]).
      - optabs-libfuncs.[hc]: optabs-specific libfuncs (an extension of
          libfuncs.h)
      - optabs.h: For now includes optabs-query.h and optabs-libfuncs.h.

Only two files outside optabs need to include both optabs.h and
optabs-tree.h: expr.c and function.c.  I think that's expected given
that both are related to expand.

It might be good to split optabs.h further, but this is already quite
a big patch.

I changed can_conditionally_move_p from returning an int to returning
a bool and fixed a few formatting glitches.  There should be no other
changes to the functions themselves.

gcc/
	* Makefile.in (OBJS): Add optabs-libfuncs.o, optabs-query.o
	and optabs-tree.o.
	(GTFILES): Replace optabs.c with optabs-libfunc.c.
	* genopinit.c (main): Add an include guard to insn-opinit.h.
	Protect the rtx_code parts with NUM_RTX_CODE.
	* optabs.h: Split parts out to...
	* optabs-libfuncs.h, optabs-query.h, optabs-tree.h: ...these
	new files.
	* optabs.c: Split parts out to...
	* optabs-libfuncs.c, optabs-query.c, optabs-tree.c: ...these
	new files.
	* cilk-common.c: Include optabs-query.h rather than optabs.h.
	* fold-const.c: Likewise.
	* target-globals.c: Likewise.
	* tree-if-conv.c: Likewise.
	* tree-ssa-forwprop.c: Likewise.
	* tree-ssa-loop-prefetch.c: Likewise.
	* tree-ssa-math-opts.c: Include optabs-tree.h rather than
	optabs.h.  Remove unncessary include files.
	* tree-ssa-phiopt.c: Likewise.
	* tree-ssa-reassoc.c: Likewise.
	* tree-switch-conversion.c: Likewise.
	* tree-vect-data-refs.c: Likewise.
	* tree-vect-generic.c: Likewise.
	* tree-vect-loop.c: Likewise.
	* tree-vect-patterns.c: Likewise.
	* tree-vect-slp.c: Likewise.
	* tree-vect-stmts.c: Likewise.
	* tree-vrp.c: Likewise.
	* toplev.c: Include optabs-query.h and optabs-libfuncs.h
	rather than optabs.h.
	* expr.c: Include optabs-tree.h.
	* function.c: Likewise.

From-SVN: r227865
This commit is contained in:
Richard Sandiford 2015-09-17 14:28:59 +00:00 committed by Richard Sandiford
parent a78eb72ac0
commit 385399a875
31 changed files with 2248 additions and 2188 deletions

View File

@ -1,3 +1,39 @@
2015-09-17 Richard Sandiford <richard.sandiford@arm.com>
* Makefile.in (OBJS): Add optabs-libfuncs.o, optabs-query.o
and optabs-tree.o.
(GTFILES): Replace optabs.c with optabs-libfunc.c.
* genopinit.c (main): Add an include guard to insn-opinit.h.
Protect the rtx_code parts with NUM_RTX_CODE.
* optabs.h: Split parts out to...
* optabs-libfuncs.h, optabs-query.h, optabs-tree.h: ...these
new files.
* optabs.c: Split parts out to...
* optabs-libfuncs.c, optabs-query.c, optabs-tree.c: ...these
new files.
* cilk-common.c: Include optabs-query.h rather than optabs.h.
* fold-const.c: Likewise.
* target-globals.c: Likewise.
* tree-if-conv.c: Likewise.
* tree-ssa-forwprop.c: Likewise.
* tree-ssa-loop-prefetch.c: Likewise.
* tree-ssa-math-opts.c: Include optabs-tree.h rather than
optabs.h. Remove unncessary include files.
* tree-ssa-phiopt.c: Likewise.
* tree-ssa-reassoc.c: Likewise.
* tree-switch-conversion.c: Likewise.
* tree-vect-data-refs.c: Likewise.
* tree-vect-generic.c: Likewise.
* tree-vect-loop.c: Likewise.
* tree-vect-patterns.c: Likewise.
* tree-vect-slp.c: Likewise.
* tree-vect-stmts.c: Likewise.
* tree-vrp.c: Likewise.
* toplev.c: Include optabs-query.h and optabs-libfuncs.h
rather than optabs.h.
* expr.c: Include optabs-tree.h.
* function.c: Likewise.
2015-09-17 Eric Botcazou <ebotcazou@adacore.com>
PR middle-end/65958

View File

@ -1350,6 +1350,9 @@ OBJS = \
modulo-sched.o \
omp-low.o \
optabs.o \
optabs-libfuncs.o \
optabs-query.o \
optabs-tree.o \
options-save.o \
opts-global.o \
passes.o \
@ -2330,7 +2333,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/expr.h \
$(srcdir)/function.c $(srcdir)/except.c \
$(srcdir)/gcse.c $(srcdir)/godump.c \
$(srcdir)/lists.c $(srcdir)/optabs.c \
$(srcdir)/lists.c $(srcdir)/optabs-libfuncs.c \
$(srcdir)/profile.c $(srcdir)/mcf.c \
$(srcdir)/reg-stack.c $(srcdir)/cfgrtl.c \
$(srcdir)/sdbout.c $(srcdir)/stor-layout.c \

View File

@ -44,7 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-query.h"
#include "recog.h"
#include "tree-iterator.h"
#include "gimplify.h"

View File

@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
#include "expr.h"
#include "insn-codes.h"
#include "optabs-tree.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"

View File

@ -76,7 +76,7 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "cgraph.h"
#include "generic-match.h"
#include "optabs.h"
#include "optabs-query.h"
#ifndef LOAD_EXTEND_OP
#define LOAD_EXTEND_OP(M) UNKNOWN

View File

@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs-tree.h"
#include "optabs.h"
#include "libfuncs.h"
#include "regs.h"

View File

@ -377,6 +377,9 @@ main (int argc, char **argv)
purging of the X patterns above. */
qsort (optabs, n, sizeof (optab_def), optab_kind_cmp);
fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n");
fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n");
/* Emit the optab enumeration for the header file. */
fprintf (h_file, "enum optab_tag {\n");
for (i = j = 0; i < n; ++i)
@ -426,6 +429,7 @@ main (int argc, char **argv)
" the body of that kind of insn. */\n"
"#define GEN_FCN(CODE) (insn_data[CODE].genfun)\n"
"\n"
"#ifdef NUM_RTX_CODE\n"
"/* Contains the optab used for each rtx code, and vice-versa. */\n"
"extern const optab code_to_optab_[NUM_RTX_CODE];\n"
"extern const enum rtx_code optab_to_code_[NUM_OPTABS];\n"
@ -441,6 +445,7 @@ main (int argc, char **argv)
"{\n"
" return optab_to_code_[op];\n"
"}\n"
"#endif\n"
"\n"
"extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
"extern const struct optab_libcall_d normlib_def[NUM_NORMLIB_OPTABS];\n"
@ -594,6 +599,7 @@ main (int argc, char **argv)
}
fprintf (s_file, "};\n\n");
fprintf (h_file, "#endif\n");
return (fclose (h_file) == 0 && fclose (s_file) == 0
? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
}

974
gcc/optabs-libfuncs.c Normal file
View File

@ -0,0 +1,974 @@
/* Mapping from optabs to underlying library functions
Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "insn-codes.h"
#include "optabs-libfuncs.h"
#include "libfuncs.h"
#include "optabs-query.h"
#include "tree.h"
#include "stringpool.h"
#include "varasm.h"
#include "stor-layout.h"
#include "rtl.h"
struct target_libfuncs default_target_libfuncs;
#if SWITCHABLE_TARGET
struct target_libfuncs *this_target_libfuncs = &default_target_libfuncs;
#endif
#define libfunc_hash \
(this_target_libfuncs->x_libfunc_hash)
/* Prefixes for the current version of decimal floating point (BID vs. DPD) */
#if ENABLE_DECIMAL_BID_FORMAT
#define DECIMAL_PREFIX "bid_"
#else
#define DECIMAL_PREFIX "dpd_"
#endif
/* Used for libfunc_hash. */
hashval_t
libfunc_hasher::hash (libfunc_entry *e)
{
return ((e->mode1 + e->mode2 * NUM_MACHINE_MODES) ^ e->op);
}
/* Used for libfunc_hash. */
bool
libfunc_hasher::equal (libfunc_entry *e1, libfunc_entry *e2)
{
return e1->op == e2->op && e1->mode1 == e2->mode1 && e1->mode2 == e2->mode2;
}
/* Return libfunc corresponding operation defined by OPTAB converting
from MODE2 to MODE1. Trigger lazy initialization if needed, return NULL
if no libfunc is available. */
rtx
convert_optab_libfunc (convert_optab optab, machine_mode mode1,
machine_mode mode2)
{
struct libfunc_entry e;
struct libfunc_entry **slot;
/* ??? This ought to be an assert, but not all of the places
that we expand optabs know about the optabs that got moved
to being direct. */
if (!(optab >= FIRST_CONV_OPTAB && optab <= LAST_CONVLIB_OPTAB))
return NULL_RTX;
e.op = optab;
e.mode1 = mode1;
e.mode2 = mode2;
slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
{
const struct convert_optab_libcall_d *d
= &convlib_def[optab - FIRST_CONV_OPTAB];
if (d->libcall_gen == NULL)
return NULL;
d->libcall_gen (optab, d->libcall_basename, mode1, mode2);
slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
return NULL;
}
return (*slot)->libfunc;
}
/* Return libfunc corresponding operation defined by OPTAB in MODE.
Trigger lazy initialization if needed, return NULL if no libfunc is
available. */
rtx
optab_libfunc (optab optab, machine_mode mode)
{
struct libfunc_entry e;
struct libfunc_entry **slot;
/* ??? This ought to be an assert, but not all of the places
that we expand optabs know about the optabs that got moved
to being direct. */
if (!(optab >= FIRST_NORM_OPTAB && optab <= LAST_NORMLIB_OPTAB))
return NULL_RTX;
e.op = optab;
e.mode1 = mode;
e.mode2 = VOIDmode;
slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
{
const struct optab_libcall_d *d
= &normlib_def[optab - FIRST_NORM_OPTAB];
if (d->libcall_gen == NULL)
return NULL;
d->libcall_gen (optab, d->libcall_basename, d->libcall_suffix, mode);
slot = libfunc_hash->find_slot (&e, NO_INSERT);
if (!slot)
return NULL;
}
return (*slot)->libfunc;
}
/* 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 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').
OPTABLE is the table in which libfunc fields are to be initialized.
OPNAME is the generic (string) name of the operation.
SUFFIX is the character which specifies the number of operands for
the given generic operation.
MODE is the mode to generate for. */
static void
gen_libfunc (optab optable, const char *opname, int suffix,
machine_mode mode)
{
unsigned opname_len = strlen (opname);
const char *mname = GET_MODE_NAME (mode);
unsigned mname_len = strlen (mname);
int prefix_len = targetm.libfunc_gnu_prefix ? 6 : 2;
int len = prefix_len + opname_len + mname_len + 1 + 1;
char *libfunc_name = XALLOCAVEC (char, len);
char *p;
const char *q;
p = libfunc_name;
*p++ = '_';
*p++ = '_';
if (targetm.libfunc_gnu_prefix)
{
*p++ = 'g';
*p++ = 'n';
*p++ = 'u';
*p++ = '_';
}
for (q = opname; *q;)
*p++ = *q++;
for (q = mname; *q; q++)
*p++ = TOLOWER (*q);
*p++ = suffix;
*p = '\0';
set_optab_libfunc (optable, mode,
ggc_alloc_string (libfunc_name, p - libfunc_name));
}
/* Like gen_libfunc, but verify that integer operation is involved. */
void
gen_int_libfunc (optab optable, const char *opname, char suffix,
machine_mode mode)
{
int maxsize = 2 * BITS_PER_WORD;
int minsize = BITS_PER_WORD;
if (GET_MODE_CLASS (mode) != MODE_INT)
return;
if (maxsize < LONG_LONG_TYPE_SIZE)
maxsize = LONG_LONG_TYPE_SIZE;
if (minsize > INT_TYPE_SIZE
&& (trapv_binoptab_p (optable)
|| trapv_unoptab_p (optable)))
minsize = INT_TYPE_SIZE;
if (GET_MODE_BITSIZE (mode) < minsize
|| GET_MODE_BITSIZE (mode) > maxsize)
return;
gen_libfunc (optable, opname, suffix, mode);
}
/* Like gen_libfunc, but verify that FP and set decimal prefix if needed. */
void
gen_fp_libfunc (optab optable, const char *opname, char suffix,
machine_mode mode)
{
char *dec_opname;
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_libfunc (optable, opname, suffix, mode);
if (DECIMAL_FLOAT_MODE_P (mode))
{
dec_opname = XALLOCAVEC (char, sizeof (DECIMAL_PREFIX) + strlen (opname));
/* For BID support, change the name to have either a bid_ or dpd_ prefix
depending on the low level floating format used. */
memcpy (dec_opname, DECIMAL_PREFIX, sizeof (DECIMAL_PREFIX) - 1);
strcpy (dec_opname + sizeof (DECIMAL_PREFIX) - 1, opname);
gen_libfunc (optable, dec_opname, suffix, mode);
}
}
/* Like gen_libfunc, but verify that fixed-point operation is involved. */
void
gen_fixed_libfunc (optab optable, const char *opname, char suffix,
machine_mode mode)
{
if (!ALL_FIXED_POINT_MODE_P (mode))
return;
gen_libfunc (optable, opname, suffix, mode);
}
/* Like gen_libfunc, but verify that signed fixed-point operation is
involved. */
void
gen_signed_fixed_libfunc (optab optable, const char *opname, char suffix,
machine_mode mode)
{
if (!SIGNED_FIXED_POINT_MODE_P (mode))
return;
gen_libfunc (optable, opname, suffix, mode);
}
/* Like gen_libfunc, but verify that unsigned fixed-point operation is
involved. */
void
gen_unsigned_fixed_libfunc (optab optable, const char *opname, char suffix,
machine_mode mode)
{
if (!UNSIGNED_FIXED_POINT_MODE_P (mode))
return;
gen_libfunc (optable, opname, suffix, mode);
}
/* Like gen_libfunc, but verify that FP or INT operation is involved. */
void
gen_int_fp_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
}
/* Like gen_libfunc, but verify that FP or INT operation is involved
and add 'v' suffix for integer operation. */
void
gen_intv_fp_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
if (GET_MODE_CLASS (mode) == MODE_INT)
{
int len = strlen (name);
char *v_name = XALLOCAVEC (char, len + 2);
strcpy (v_name, name);
v_name[len] = 'v';
v_name[len + 1] = 0;
gen_int_libfunc (optable, v_name, suffix, mode);
}
}
/* Like gen_libfunc, but verify that FP or INT or FIXED operation is
involved. */
void
gen_int_fp_fixed_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
if (ALL_FIXED_POINT_MODE_P (mode))
gen_fixed_libfunc (optable, name, suffix, mode);
}
/* Like gen_libfunc, but verify that FP or INT or signed FIXED operation is
involved. */
void
gen_int_fp_signed_fixed_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
gen_fp_libfunc (optable, name, suffix, mode);
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
if (SIGNED_FIXED_POINT_MODE_P (mode))
gen_signed_fixed_libfunc (optable, name, suffix, mode);
}
/* Like gen_libfunc, but verify that INT or FIXED operation is
involved. */
void
gen_int_fixed_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
if (ALL_FIXED_POINT_MODE_P (mode))
gen_fixed_libfunc (optable, name, suffix, mode);
}
/* Like gen_libfunc, but verify that INT or signed FIXED operation is
involved. */
void
gen_int_signed_fixed_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
if (SIGNED_FIXED_POINT_MODE_P (mode))
gen_signed_fixed_libfunc (optable, name, suffix, mode);
}
/* Like gen_libfunc, but verify that INT or unsigned FIXED operation is
involved. */
void
gen_int_unsigned_fixed_libfunc (optab optable, const char *name, char suffix,
machine_mode mode)
{
if (INTEGRAL_MODE_P (mode))
gen_int_libfunc (optable, name, suffix, mode);
if (UNSIGNED_FIXED_POINT_MODE_P (mode))
gen_unsigned_fixed_libfunc (optable, name, suffix, mode);
}
/* 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. */
void
gen_interclass_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
size_t opname_len = strlen (opname);
size_t mname_len = 0;
const char *fname, *tname;
const char *q;
int prefix_len = targetm.libfunc_gnu_prefix ? 6 : 2;
char *libfunc_name, *suffix;
char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
char *p;
/* If this is a decimal conversion, add the current BID vs. DPD prefix that
depends on which underlying decimal floating point format is used. */
const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
nondec_name = XALLOCAVEC (char, prefix_len + opname_len + mname_len + 1 + 1);
nondec_name[0] = '_';
nondec_name[1] = '_';
if (targetm.libfunc_gnu_prefix)
{
nondec_name[2] = 'g';
nondec_name[3] = 'n';
nondec_name[4] = 'u';
nondec_name[5] = '_';
}
memcpy (&nondec_name[prefix_len], opname, opname_len);
nondec_suffix = nondec_name + opname_len + prefix_len;
dec_name = XALLOCAVEC (char, 2 + dec_len + opname_len + mname_len + 1 + 1);
dec_name[0] = '_';
dec_name[1] = '_';
memcpy (&dec_name[2], DECIMAL_PREFIX, dec_len);
memcpy (&dec_name[2+dec_len], opname, opname_len);
dec_suffix = dec_name + dec_len + opname_len + 2;
fname = GET_MODE_NAME (fmode);
tname = GET_MODE_NAME (tmode);
if (DECIMAL_FLOAT_MODE_P (fmode) || DECIMAL_FLOAT_MODE_P (tmode))
{
libfunc_name = dec_name;
suffix = dec_suffix;
}
else
{
libfunc_name = nondec_name;
suffix = nondec_suffix;
}
p = suffix;
for (q = fname; *q; p++, q++)
*p = TOLOWER (*q);
for (q = tname; *q; p++, q++)
*p = TOLOWER (*q);
*p = '\0';
set_conv_libfunc (tab, tmode, fmode,
ggc_alloc_string (libfunc_name, p - libfunc_name));
}
/* Same as gen_interclass_conv_libfunc but verify that we are producing
int->fp conversion. */
void
gen_int_to_fp_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (GET_MODE_CLASS (fmode) != MODE_INT)
return;
if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
return;
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* ufloat_optab is special by using floatun for FP and floatuns decimal fp
naming scheme. */
void
gen_ufloat_conv_libfunc (convert_optab tab,
const char *opname ATTRIBUTE_UNUSED,
machine_mode tmode,
machine_mode fmode)
{
if (DECIMAL_FLOAT_MODE_P (tmode))
gen_int_to_fp_conv_libfunc (tab, "floatuns", tmode, fmode);
else
gen_int_to_fp_conv_libfunc (tab, "floatun", tmode, fmode);
}
/* Same as gen_interclass_conv_libfunc but verify that we are producing
fp->int conversion. */
void
gen_int_to_fp_nondecimal_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (GET_MODE_CLASS (fmode) != MODE_INT)
return;
if (GET_MODE_CLASS (tmode) != MODE_FLOAT)
return;
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Same as gen_interclass_conv_libfunc but verify that we are producing
fp->int conversion with no decimal floating point involved. */
void
gen_fp_to_int_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
return;
if (GET_MODE_CLASS (tmode) != MODE_INT)
return;
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Initialize the libfunc fields of an of an intra-mode-class conversion optab.
The string formation rules are
similar to the ones for init_libfunc, above. */
void
gen_intraclass_conv_libfunc (convert_optab tab, const char *opname,
machine_mode tmode, machine_mode fmode)
{
size_t opname_len = strlen (opname);
size_t mname_len = 0;
const char *fname, *tname;
const char *q;
int prefix_len = targetm.libfunc_gnu_prefix ? 6 : 2;
char *nondec_name, *dec_name, *nondec_suffix, *dec_suffix;
char *libfunc_name, *suffix;
char *p;
/* If this is a decimal conversion, add the current BID vs. DPD prefix that
depends on which underlying decimal floating point format is used. */
const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
nondec_name = XALLOCAVEC (char, 2 + opname_len + mname_len + 1 + 1);
nondec_name[0] = '_';
nondec_name[1] = '_';
if (targetm.libfunc_gnu_prefix)
{
nondec_name[2] = 'g';
nondec_name[3] = 'n';
nondec_name[4] = 'u';
nondec_name[5] = '_';
}
memcpy (&nondec_name[prefix_len], opname, opname_len);
nondec_suffix = nondec_name + opname_len + prefix_len;
dec_name = XALLOCAVEC (char, 2 + dec_len + opname_len + mname_len + 1 + 1);
dec_name[0] = '_';
dec_name[1] = '_';
memcpy (&dec_name[2], DECIMAL_PREFIX, dec_len);
memcpy (&dec_name[2 + dec_len], opname, opname_len);
dec_suffix = dec_name + dec_len + opname_len + 2;
fname = GET_MODE_NAME (fmode);
tname = GET_MODE_NAME (tmode);
if (DECIMAL_FLOAT_MODE_P (fmode) || DECIMAL_FLOAT_MODE_P (tmode))
{
libfunc_name = dec_name;
suffix = dec_suffix;
}
else
{
libfunc_name = nondec_name;
suffix = nondec_suffix;
}
p = suffix;
for (q = fname; *q; p++, q++)
*p = TOLOWER (*q);
for (q = tname; *q; p++, q++)
*p = TOLOWER (*q);
*p++ = '2';
*p = '\0';
set_conv_libfunc (tab, tmode, fmode,
ggc_alloc_string (libfunc_name, p - libfunc_name));
}
/* Pick proper libcall for trunc_optab. We need to chose if we do
truncation or extension and interclass or intraclass. */
void
gen_trunc_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
return;
if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
return;
if (tmode == fmode)
return;
if ((GET_MODE_CLASS (tmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (fmode))
|| (GET_MODE_CLASS (fmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (tmode)))
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
if (GET_MODE_PRECISION (fmode) <= GET_MODE_PRECISION (tmode))
return;
if ((GET_MODE_CLASS (tmode) == MODE_FLOAT
&& GET_MODE_CLASS (fmode) == MODE_FLOAT)
|| (DECIMAL_FLOAT_MODE_P (fmode) && DECIMAL_FLOAT_MODE_P (tmode)))
gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Pick proper libcall for extend_optab. We need to chose if we do
truncation or extension and interclass or intraclass. */
void
gen_extend_conv_libfunc (convert_optab tab,
const char *opname ATTRIBUTE_UNUSED,
machine_mode tmode,
machine_mode fmode)
{
if (GET_MODE_CLASS (tmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (tmode))
return;
if (GET_MODE_CLASS (fmode) != MODE_FLOAT && !DECIMAL_FLOAT_MODE_P (fmode))
return;
if (tmode == fmode)
return;
if ((GET_MODE_CLASS (tmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (fmode))
|| (GET_MODE_CLASS (fmode) == MODE_FLOAT && DECIMAL_FLOAT_MODE_P (tmode)))
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
if (GET_MODE_PRECISION (fmode) > GET_MODE_PRECISION (tmode))
return;
if ((GET_MODE_CLASS (tmode) == MODE_FLOAT
&& GET_MODE_CLASS (fmode) == MODE_FLOAT)
|| (DECIMAL_FLOAT_MODE_P (fmode) && DECIMAL_FLOAT_MODE_P (tmode)))
gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Pick proper libcall for fract_optab. We need to chose if we do
interclass or intraclass. */
void
gen_fract_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (tmode == fmode)
return;
if (!(ALL_FIXED_POINT_MODE_P (tmode) || ALL_FIXED_POINT_MODE_P (fmode)))
return;
if (GET_MODE_CLASS (tmode) == GET_MODE_CLASS (fmode))
gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
else
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Pick proper libcall for fractuns_optab. */
void
gen_fractuns_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (tmode == fmode)
return;
/* One mode must be a fixed-point mode, and the other must be an integer
mode. */
if (!((ALL_FIXED_POINT_MODE_P (tmode) && GET_MODE_CLASS (fmode) == MODE_INT)
|| (ALL_FIXED_POINT_MODE_P (fmode)
&& GET_MODE_CLASS (tmode) == MODE_INT)))
return;
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Pick proper libcall for satfract_optab. We need to chose if we do
interclass or intraclass. */
void
gen_satfract_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (tmode == fmode)
return;
/* TMODE must be a fixed-point mode. */
if (!ALL_FIXED_POINT_MODE_P (tmode))
return;
if (GET_MODE_CLASS (tmode) == GET_MODE_CLASS (fmode))
gen_intraclass_conv_libfunc (tab, opname, tmode, fmode);
else
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Pick proper libcall for satfractuns_optab. */
void
gen_satfractuns_conv_libfunc (convert_optab tab,
const char *opname,
machine_mode tmode,
machine_mode fmode)
{
if (tmode == fmode)
return;
/* TMODE must be a fixed-point mode, and FMODE must be an integer mode. */
if (!(ALL_FIXED_POINT_MODE_P (tmode) && GET_MODE_CLASS (fmode) == MODE_INT))
return;
gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
}
/* Hashtable callbacks for libfunc_decls. */
struct libfunc_decl_hasher : ggc_ptr_hash<tree_node>
{
static hashval_t
hash (tree entry)
{
return IDENTIFIER_HASH_VALUE (DECL_NAME (entry));
}
static bool
equal (tree decl, tree name)
{
return DECL_NAME (decl) == name;
}
};
/* A table of previously-created libfuncs, hashed by name. */
static GTY (()) hash_table<libfunc_decl_hasher> *libfunc_decls;
/* Build a decl for a libfunc named NAME. */
tree
build_libfunc_function (const char *name)
{
tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
get_identifier (name),
build_function_type (integer_type_node, NULL_TREE));
/* ??? We don't have any type information except for this is
a function. Pretend this is "int foo ()". */
DECL_ARTIFICIAL (decl) = 1;
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
gcc_assert (DECL_ASSEMBLER_NAME (decl));
/* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with
are the flags assigned by targetm.encode_section_info. */
SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
return decl;
}
/* Return a libfunc for NAME, creating one if we don't already have one.
The returned rtx is a SYMBOL_REF. */
rtx
init_one_libfunc (const char *name)
{
tree id, decl;
hashval_t hash;
if (libfunc_decls == NULL)
libfunc_decls = hash_table<libfunc_decl_hasher>::create_ggc (37);
/* See if we have already created a libfunc decl for this function. */
id = get_identifier (name);
hash = IDENTIFIER_HASH_VALUE (id);
tree *slot = libfunc_decls->find_slot_with_hash (id, hash, INSERT);
decl = *slot;
if (decl == NULL)
{
/* Create a new decl, so that it can be passed to
targetm.encode_section_info. */
decl = build_libfunc_function (name);
*slot = decl;
}
return XEXP (DECL_RTL (decl), 0);
}
/* Adjust the assembler name of libfunc NAME to ASMSPEC. */
rtx
set_user_assembler_libfunc (const char *name, const char *asmspec)
{
tree id, decl;
hashval_t hash;
id = get_identifier (name);
hash = IDENTIFIER_HASH_VALUE (id);
tree *slot = libfunc_decls->find_slot_with_hash (id, hash, NO_INSERT);
gcc_assert (slot);
decl = (tree) *slot;
set_user_assembler_name (decl, asmspec);
return XEXP (DECL_RTL (decl), 0);
}
/* 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 op, machine_mode mode, const char *name)
{
rtx val;
struct libfunc_entry e;
struct libfunc_entry **slot;
e.op = op;
e.mode1 = mode;
e.mode2 = VOIDmode;
if (name)
val = init_one_libfunc (name);
else
val = 0;
slot = libfunc_hash->find_slot (&e, INSERT);
if (*slot == NULL)
*slot = ggc_alloc<libfunc_entry> ();
(*slot)->op = op;
(*slot)->mode1 = mode;
(*slot)->mode2 = VOIDmode;
(*slot)->libfunc = val;
}
/* 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 optab, machine_mode tmode,
machine_mode fmode, const char *name)
{
rtx val;
struct libfunc_entry e;
struct libfunc_entry **slot;
e.op = optab;
e.mode1 = tmode;
e.mode2 = fmode;
if (name)
val = init_one_libfunc (name);
else
val = 0;
slot = libfunc_hash->find_slot (&e, INSERT);
if (*slot == NULL)
*slot = ggc_alloc<libfunc_entry> ();
(*slot)->op = optab;
(*slot)->mode1 = tmode;
(*slot)->mode2 = fmode;
(*slot)->libfunc = val;
}
/* Call this to initialize the contents of the optabs
appropriately for the current target machine. */
void
init_optabs (void)
{
if (libfunc_hash)
libfunc_hash->empty ();
else
libfunc_hash = hash_table<libfunc_hasher>::create_ggc (10);
/* Fill in the optabs with the insns we support. */
init_all_optabs (this_fn_optabs);
/* The ffs function operates on `int'. Fall back on it if we do not
have a libgcc2 function for that width. */
if (INT_TYPE_SIZE < BITS_PER_WORD)
set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, MODE_INT, 0),
"ffs");
/* Explicitly initialize the bswap libfuncs since we need them to be
valid for things other than word_mode. */
if (targetm.libfunc_gnu_prefix)
{
set_optab_libfunc (bswap_optab, SImode, "__gnu_bswapsi2");
set_optab_libfunc (bswap_optab, DImode, "__gnu_bswapdi2");
}
else
{
set_optab_libfunc (bswap_optab, SImode, "__bswapsi2");
set_optab_libfunc (bswap_optab, DImode, "__bswapdi2");
}
/* 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)
set_optab_libfunc (abs_optab, TYPE_MODE (complex_double_type_node),
"cabs");
abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
memmove_libfunc = init_one_libfunc ("memmove");
memcmp_libfunc = init_one_libfunc ("memcmp");
memset_libfunc = init_one_libfunc ("memset");
setbits_libfunc = init_one_libfunc ("__setbits");
#ifndef DONT_USE_BUILTIN_SETJMP
setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
#else
setjmp_libfunc = init_one_libfunc ("setjmp");
longjmp_libfunc = init_one_libfunc ("longjmp");
#endif
unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
unwind_sjlj_unregister_libfunc
= init_one_libfunc ("_Unwind_SjLj_Unregister");
/* 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");
/* Allow the target to add more libcalls or rename some, etc. */
targetm.init_libfuncs ();
}
/* A helper function for init_sync_libfuncs. Using the basename BASE,
install libfuncs into TAB for BASE_N for 1 <= N <= MAX. */
static void
init_sync_libfuncs_1 (optab tab, const char *base, int max)
{
machine_mode mode;
char buf[64];
size_t len = strlen (base);
int i;
gcc_assert (max <= 8);
gcc_assert (len + 3 < sizeof (buf));
memcpy (buf, base, len);
buf[len] = '_';
buf[len + 1] = '0';
buf[len + 2] = '\0';
mode = QImode;
for (i = 1; i <= max; i *= 2)
{
buf[len + 1] = '0' + i;
set_optab_libfunc (tab, mode, buf);
mode = GET_MODE_2XWIDER_MODE (mode);
}
}
void
init_sync_libfuncs (int max)
{
if (!flag_sync_libcalls)
return;
init_sync_libfuncs_1 (sync_compare_and_swap_optab,
"__sync_val_compare_and_swap", max);
init_sync_libfuncs_1 (sync_lock_test_and_set_optab,
"__sync_lock_test_and_set", max);
init_sync_libfuncs_1 (sync_old_add_optab, "__sync_fetch_and_add", max);
init_sync_libfuncs_1 (sync_old_sub_optab, "__sync_fetch_and_sub", max);
init_sync_libfuncs_1 (sync_old_ior_optab, "__sync_fetch_and_or", max);
init_sync_libfuncs_1 (sync_old_and_optab, "__sync_fetch_and_and", max);
init_sync_libfuncs_1 (sync_old_xor_optab, "__sync_fetch_and_xor", max);
init_sync_libfuncs_1 (sync_old_nand_optab, "__sync_fetch_and_nand", max);
init_sync_libfuncs_1 (sync_new_add_optab, "__sync_add_and_fetch", max);
init_sync_libfuncs_1 (sync_new_sub_optab, "__sync_sub_and_fetch", max);
init_sync_libfuncs_1 (sync_new_ior_optab, "__sync_or_and_fetch", max);
init_sync_libfuncs_1 (sync_new_and_optab, "__sync_and_and_fetch", max);
init_sync_libfuncs_1 (sync_new_xor_optab, "__sync_xor_and_fetch", max);
init_sync_libfuncs_1 (sync_new_nand_optab, "__sync_nand_and_fetch", max);
}
#include "gt-optabs-libfuncs.h"

77
gcc/optabs-libfuncs.h Normal file
View File

@ -0,0 +1,77 @@
/* Mapping from optabs to underlying library functions
Copyright (C) 2001-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_OPTABS_LIBFUNCS_H
#define GCC_OPTABS_LIBFUNCS_H
#include "insn-opinit.h"
rtx convert_optab_libfunc (convert_optab, machine_mode, machine_mode);
rtx optab_libfunc (optab, machine_mode);
void gen_int_libfunc (optab, const char *, char, machine_mode);
void gen_fp_libfunc (optab, const char *, char, machine_mode);
void gen_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_signed_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_unsigned_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_int_fp_libfunc (optab, const char *, char, machine_mode);
void gen_intv_fp_libfunc (optab, const char *, char, machine_mode);
void gen_int_fp_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_int_fp_signed_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_int_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_int_signed_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_int_unsigned_fixed_libfunc (optab, const char *, char, machine_mode);
void gen_interclass_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_int_to_fp_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_ufloat_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_int_to_fp_nondecimal_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_fp_to_int_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_intraclass_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_trunc_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_extend_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_fract_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_fractuns_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_satfract_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
void gen_satfractuns_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
tree build_libfunc_function (const char *);
rtx init_one_libfunc (const char *);
rtx set_user_assembler_libfunc (const char *, const char *);
void set_optab_libfunc (optab, machine_mode, const char *);
void set_conv_libfunc (convert_optab, machine_mode,
machine_mode, const char *);
void init_optabs (void);
void init_sync_libfuncs (int max);
#endif

573
gcc/optabs-query.c Normal file
View File

@ -0,0 +1,573 @@
/* IR-agnostic target query functions relating to optabs
Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "insn-codes.h"
#include "optabs-query.h"
#include "optabs-libfuncs.h"
#include "insn-config.h"
#include "rtl.h"
#include "recog.h"
struct target_optabs default_target_optabs;
struct target_optabs *this_fn_optabs = &default_target_optabs;
#if SWITCHABLE_TARGET
struct target_optabs *this_target_optabs = &default_target_optabs;
#endif
/* Enumerates the possible types of structure operand to an
extraction_insn. */
enum extraction_type { ET_unaligned_mem, ET_reg };
/* Check whether insv, extv or extzv pattern ICODE can be used for an
insertion or extraction of type TYPE on a structure of mode MODE.
Return true if so and fill in *INSN accordingly. STRUCT_OP is the
operand number of the structure (the first sign_extract or zero_extract
operand) and FIELD_OP is the operand number of the field (the other
side of the set from the sign_extract or zero_extract). */
static bool
get_traditional_extraction_insn (extraction_insn *insn,
enum extraction_type type,
machine_mode mode,
enum insn_code icode,
int struct_op, int field_op)
{
const struct insn_data_d *data = &insn_data[icode];
machine_mode struct_mode = data->operand[struct_op].mode;
if (struct_mode == VOIDmode)
struct_mode = word_mode;
if (mode != struct_mode)
return false;
machine_mode field_mode = data->operand[field_op].mode;
if (field_mode == VOIDmode)
field_mode = word_mode;
machine_mode pos_mode = data->operand[struct_op + 2].mode;
if (pos_mode == VOIDmode)
pos_mode = word_mode;
insn->icode = icode;
insn->field_mode = field_mode;
insn->struct_mode = (type == ET_unaligned_mem ? byte_mode : struct_mode);
insn->pos_mode = pos_mode;
return true;
}
/* Return true if an optab exists to perform an insertion or extraction
of type TYPE in mode MODE. Describe the instruction in *INSN if so.
REG_OPTAB is the optab to use for register structures and
MISALIGN_OPTAB is the optab to use for misaligned memory structures.
POS_OP is the operand number of the bit position. */
static bool
get_optab_extraction_insn (struct extraction_insn *insn,
enum extraction_type type,
machine_mode mode, direct_optab reg_optab,
direct_optab misalign_optab, int pos_op)
{
direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
enum insn_code icode = direct_optab_handler (optab, mode);
if (icode == CODE_FOR_nothing)
return false;
const struct insn_data_d *data = &insn_data[icode];
insn->icode = icode;
insn->field_mode = mode;
insn->struct_mode = (type == ET_unaligned_mem ? BLKmode : mode);
insn->pos_mode = data->operand[pos_op].mode;
if (insn->pos_mode == VOIDmode)
insn->pos_mode = word_mode;
return true;
}
/* Return true if an instruction exists to perform an insertion or
extraction (PATTERN says which) of type TYPE in mode MODE.
Describe the instruction in *INSN if so. */
static bool
get_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
enum extraction_type type,
machine_mode mode)
{
switch (pattern)
{
case EP_insv:
if (targetm.have_insv ()
&& get_traditional_extraction_insn (insn, type, mode,
targetm.code_for_insv, 0, 3))
return true;
return get_optab_extraction_insn (insn, type, mode, insv_optab,
insvmisalign_optab, 2);
case EP_extv:
if (targetm.have_extv ()
&& get_traditional_extraction_insn (insn, type, mode,
targetm.code_for_extv, 1, 0))
return true;
return get_optab_extraction_insn (insn, type, mode, extv_optab,
extvmisalign_optab, 3);
case EP_extzv:
if (targetm.have_extzv ()
&& get_traditional_extraction_insn (insn, type, mode,
targetm.code_for_extzv, 1, 0))
return true;
return get_optab_extraction_insn (insn, type, mode, extzv_optab,
extzvmisalign_optab, 3);
default:
gcc_unreachable ();
}
}
/* Return true if an instruction exists to access a field of mode
FIELDMODE in a structure that has STRUCT_BITS significant bits.
Describe the "best" such instruction in *INSN if so. PATTERN and
TYPE describe the type of insertion or extraction we want to perform.
For an insertion, the number of significant structure bits includes
all bits of the target. For an extraction, it need only include the
most significant bit of the field. Larger widths are acceptable
in both cases. */
static bool
get_best_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
enum extraction_type type,
unsigned HOST_WIDE_INT struct_bits,
machine_mode field_mode)
{
machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
while (mode != VOIDmode)
{
if (get_extraction_insn (insn, pattern, type, mode))
{
while (mode != VOIDmode
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (field_mode)
&& !TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
field_mode))
{
get_extraction_insn (insn, pattern, type, mode);
mode = GET_MODE_WIDER_MODE (mode);
}
return true;
}
mode = GET_MODE_WIDER_MODE (mode);
}
return false;
}
/* Return true if an instruction exists to access a field of mode
FIELDMODE in a register structure that has STRUCT_BITS significant bits.
Describe the "best" such instruction in *INSN if so. PATTERN describes
the type of insertion or extraction we want to perform.
For an insertion, the number of significant structure bits includes
all bits of the target. For an extraction, it need only include the
most significant bit of the field. Larger widths are acceptable
in both cases. */
bool
get_best_reg_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
unsigned HOST_WIDE_INT struct_bits,
machine_mode field_mode)
{
return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
field_mode);
}
/* Return true if an instruction exists to access a field of BITSIZE
bits starting BITNUM bits into a memory structure. Describe the
"best" such instruction in *INSN if so. PATTERN describes the type
of insertion or extraction we want to perform and FIELDMODE is the
natural mode of the extracted field.
The instructions considered here only access bytes that overlap
the bitfield; they do not touch any surrounding bytes. */
bool
get_best_mem_extraction_insn (extraction_insn *insn,
enum extraction_pattern pattern,
HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
machine_mode field_mode)
{
unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
+ bitsize
+ BITS_PER_UNIT - 1);
struct_bits -= struct_bits % BITS_PER_UNIT;
return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
struct_bits, field_mode);
}
/* Return the insn code used to extend FROM_MODE to TO_MODE.
UNSIGNEDP specifies zero-extension instead of sign-extension. If
no such operation exists, CODE_FOR_nothing will be returned. */
enum insn_code
can_extend_p (machine_mode to_mode, machine_mode from_mode,
int unsignedp)
{
if (unsignedp < 0 && targetm.have_ptr_extend ())
return targetm.code_for_ptr_extend;
convert_optab tab = unsignedp ? zext_optab : sext_optab;
return convert_optab_handler (tab, to_mode, from_mode);
}
/* Return the insn code to convert fixed-point mode FIXMODE to floating-point
mode FLTMODE, or CODE_FOR_nothing if no such instruction exists.
UNSIGNEDP specifies whether FIXMODE is unsigned. */
enum insn_code
can_float_p (machine_mode fltmode, machine_mode fixmode,
int unsignedp)
{
convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
return convert_optab_handler (tab, fltmode, fixmode);
}
/* Return the insn code to convert floating-point mode FLTMODE to fixed-point
mode FIXMODE, or CODE_FOR_nothing if no such instruction exists.
UNSIGNEDP specifies whether FIXMODE is unsigned.
On a successful return, set *TRUNCP_PTR to true if it is necessary to
output an explicit FTRUNC before the instruction. */
enum insn_code
can_fix_p (machine_mode fixmode, machine_mode fltmode,
int unsignedp, bool *truncp_ptr)
{
convert_optab tab;
enum insn_code icode;
tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
icode = convert_optab_handler (tab, fixmode, fltmode);
if (icode != CODE_FOR_nothing)
{
*truncp_ptr = false;
return icode;
}
/* FIXME: This requires a port to define both FIX and FTRUNC pattern
for this to work. We need to rework the fix* and ftrunc* patterns
and documentation. */
tab = unsignedp ? ufix_optab : sfix_optab;
icode = convert_optab_handler (tab, fixmode, fltmode);
if (icode != CODE_FOR_nothing
&& optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
{
*truncp_ptr = true;
return icode;
}
return CODE_FOR_nothing;
}
/* Return nonzero if a conditional move of mode MODE is supported.
This function is for combine so it can tell whether an insn that looks
like a conditional move is actually supported by the hardware. If we
guess wrong we lose a bit on optimization, but that's it. */
/* ??? sparc64 supports conditionally moving integers values based on fp
comparisons, and vice versa. How do we handle them? */
bool
can_conditionally_move_p (machine_mode mode)
{
return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
}
/* Return true if VEC_PERM_EXPR of arbitrary input vectors can be
expanded using SIMD extensions of the CPU. SEL may be NULL, which
stands for an unknown constant. Note that additional permutations
representing whole-vector shifts may also be handled via the vec_shr
optab, but only where the second input vector is entirely constant
zeroes; this case is not dealt with here. */
bool
can_vec_perm_p (machine_mode mode, bool variable,
const unsigned char *sel)
{
machine_mode qimode;
/* If the target doesn't implement a vector mode for the vector type,
then no operations are supported. */
if (!VECTOR_MODE_P (mode))
return false;
if (!variable)
{
if (direct_optab_handler (vec_perm_const_optab, mode) != CODE_FOR_nothing
&& (sel == NULL
|| targetm.vectorize.vec_perm_const_ok == NULL
|| targetm.vectorize.vec_perm_const_ok (mode, sel)))
return true;
}
if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
return true;
/* We allow fallback to a QI vector mode, and adjust the mask. */
if (GET_MODE_INNER (mode) == QImode)
return false;
qimode = mode_for_vector (QImode, GET_MODE_SIZE (mode));
if (!VECTOR_MODE_P (qimode))
return false;
/* ??? For completeness, we ought to check the QImode version of
vec_perm_const_optab. But all users of this implicit lowering
feature implement the variable vec_perm_optab. */
if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
return false;
/* In order to support the lowering of variable permutations,
we need to support shifts and adds. */
if (variable)
{
if (GET_MODE_UNIT_SIZE (mode) > 2
&& optab_handler (ashl_optab, mode) == CODE_FOR_nothing
&& optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
return false;
if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
return false;
}
return true;
}
/* Like optab_handler, but for widening_operations that have a
TO_MODE and a FROM_MODE. */
enum insn_code
widening_optab_handler (optab op, machine_mode to_mode,
machine_mode from_mode)
{
unsigned scode = (op << 16) | to_mode;
if (to_mode != from_mode && from_mode != VOIDmode)
{
/* ??? Why does find_widening_optab_handler_and_mode attempt to
widen things that can't be widened? E.g. add_optab... */
if (op > LAST_CONV_OPTAB)
return CODE_FOR_nothing;
scode |= from_mode << 8;
}
return raw_optab_handler (scode);
}
/* Find a widening optab even if it doesn't widen as much as we want.
E.g. if from_mode is HImode, and to_mode is DImode, and there is no
direct HI->SI insn, then return SI->DI, if that exists.
If PERMIT_NON_WIDENING is non-zero then this can be used with
non-widening optabs also. */
enum insn_code
find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
machine_mode from_mode,
int permit_non_widening,
machine_mode *found_mode)
{
for (; (permit_non_widening || from_mode != to_mode)
&& GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
&& from_mode != VOIDmode;
from_mode = GET_MODE_WIDER_MODE (from_mode))
{
enum insn_code handler = widening_optab_handler (op, to_mode,
from_mode);
if (handler != CODE_FOR_nothing)
{
if (found_mode)
*found_mode = from_mode;
return handler;
}
}
return CODE_FOR_nothing;
}
/* Return non-zero if a highpart multiply is supported of can be synthisized.
For the benefit of expand_mult_highpart, the return value is 1 for direct,
2 for even/odd widening, and 3 for hi/lo widening. */
int
can_mult_highpart_p (machine_mode mode, bool uns_p)
{
optab op;
unsigned char *sel;
unsigned i, nunits;
op = uns_p ? umul_highpart_optab : smul_highpart_optab;
if (optab_handler (op, mode) != CODE_FOR_nothing)
return 1;
/* If the mode is an integral vector, synth from widening operations. */
if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
return 0;
nunits = GET_MODE_NUNITS (mode);
sel = XALLOCAVEC (unsigned char, nunits);
op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
if (optab_handler (op, mode) != CODE_FOR_nothing)
{
op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
if (optab_handler (op, mode) != CODE_FOR_nothing)
{
for (i = 0; i < nunits; ++i)
sel[i] = !BYTES_BIG_ENDIAN + (i & ~1) + ((i & 1) ? nunits : 0);
if (can_vec_perm_p (mode, false, sel))
return 2;
}
}
op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
if (optab_handler (op, mode) != CODE_FOR_nothing)
{
op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
if (optab_handler (op, mode) != CODE_FOR_nothing)
{
for (i = 0; i < nunits; ++i)
sel[i] = 2 * i + (BYTES_BIG_ENDIAN ? 0 : 1);
if (can_vec_perm_p (mode, false, sel))
return 3;
}
}
return 0;
}
/* Return true if target supports vector masked load/store for mode. */
bool
can_vec_mask_load_store_p (machine_mode mode, bool is_load)
{
optab op = is_load ? maskload_optab : maskstore_optab;
machine_mode vmode;
unsigned int vector_sizes;
/* If mode is vector mode, check it directly. */
if (VECTOR_MODE_P (mode))
return optab_handler (op, mode) != CODE_FOR_nothing;
/* Otherwise, return true if there is some vector mode with
the mask load/store supported. */
/* See if there is any chance the mask load or store might be
vectorized. If not, punt. */
vmode = targetm.vectorize.preferred_simd_mode (mode);
if (!VECTOR_MODE_P (vmode))
return false;
if (optab_handler (op, vmode) != CODE_FOR_nothing)
return true;
vector_sizes = targetm.vectorize.autovectorize_vector_sizes ();
while (vector_sizes != 0)
{
unsigned int cur = 1 << floor_log2 (vector_sizes);
vector_sizes &= ~cur;
if (cur <= GET_MODE_SIZE (mode))
continue;
vmode = mode_for_vector (mode, cur / GET_MODE_SIZE (mode));
if (VECTOR_MODE_P (vmode)
&& optab_handler (op, vmode) != CODE_FOR_nothing)
return true;
}
return false;
}
/* Return true if there is a compare_and_swap pattern. */
bool
can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
{
enum insn_code icode;
/* Check for __atomic_compare_and_swap. */
icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
if (icode != CODE_FOR_nothing)
return true;
/* Check for __sync_compare_and_swap. */
icode = optab_handler (sync_compare_and_swap_optab, mode);
if (icode != CODE_FOR_nothing)
return true;
if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
return true;
/* No inline compare and swap. */
return false;
}
/* Return true if an atomic exchange can be performed. */
bool
can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
{
enum insn_code icode;
/* Check for __atomic_exchange. */
icode = direct_optab_handler (atomic_exchange_optab, mode);
if (icode != CODE_FOR_nothing)
return true;
/* Don't check __sync_test_and_set, as on some platforms that
has reduced functionality. Targets that really do support
a proper exchange should simply be updated to the __atomics. */
return can_compare_and_swap_p (mode, allow_libcall);
}
/* Determine whether "1 << x" is relatively cheap in word_mode. */
bool
lshift_cheap_p (bool speed_p)
{
/* FIXME: This should be made target dependent via this "this_target"
mechanism, similar to e.g. can_copy_init_p in gcse.c. */
static bool init[2] = { false, false };
static bool cheap[2] = { true, true };
/* If the targer has no lshift in word_mode, the operation will most
probably not be cheap. ??? Does GCC even work for such targets? */
if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
return false;
if (!init[speed_p])
{
rtx reg = gen_raw_REG (word_mode, 10000);
int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
word_mode, speed_p);
cheap[speed_p] = cost < COSTS_N_INSNS (3);
init[speed_p] = true;
}
return cheap[speed_p];
}

138
gcc/optabs-query.h Normal file
View File

@ -0,0 +1,138 @@
/* IR-agnostic target query functions relating to optabs
Copyright (C) 2001-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_OPTABS_QUERY_H
#define GCC_OPTABS_QUERY_H
#include "insn-opinit.h"
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
inline enum insn_code
optab_handler (optab op, machine_mode mode)
{
unsigned scode = (op << 16) | mode;
gcc_assert (op > LAST_CONV_OPTAB);
return raw_optab_handler (scode);
}
/* Return the insn used to perform conversion OP from mode FROM_MODE
to mode TO_MODE; return CODE_FOR_nothing if the target does not have
such an insn. */
inline enum insn_code
convert_optab_handler (convert_optab op, machine_mode to_mode,
machine_mode from_mode)
{
unsigned scode = (op << 16) | (from_mode << 8) | to_mode;
gcc_assert (op > unknown_optab && op <= LAST_CONV_OPTAB);
return raw_optab_handler (scode);
}
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
inline enum insn_code
direct_optab_handler (direct_optab op, machine_mode mode)
{
return optab_handler (op, mode);
}
/* Return true if UNOPTAB is for a trapping-on-overflow operation. */
inline bool
trapv_unoptab_p (optab unoptab)
{
return (unoptab == negv_optab
|| unoptab == absv_optab);
}
/* Return true if BINOPTAB is for a trapping-on-overflow operation. */
inline bool
trapv_binoptab_p (optab binoptab)
{
return (binoptab == addv_optab
|| binoptab == subv_optab
|| binoptab == smulv_optab);
}
/* Return insn code for a conditional operator with a comparison in
mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE. */
inline enum insn_code
get_vcond_icode (machine_mode vmode, machine_mode cmode, bool uns)
{
enum insn_code icode = CODE_FOR_nothing;
if (uns)
icode = convert_optab_handler (vcondu_optab, vmode, cmode);
else
icode = convert_optab_handler (vcond_optab, vmode, cmode);
return icode;
}
/* Enumerates the possible extraction_insn operations. */
enum extraction_pattern { EP_insv, EP_extv, EP_extzv };
/* Describes an instruction that inserts or extracts a bitfield. */
struct extraction_insn
{
/* The code of the instruction. */
enum insn_code icode;
/* The mode that the structure operand should have. This is byte_mode
when using the legacy insv, extv and extzv patterns to access memory. */
machine_mode struct_mode;
/* The mode of the field to be inserted or extracted, and by extension
the mode of the insertion or extraction itself. */
machine_mode field_mode;
/* The mode of the field's bit position. This is only important
when the position is variable rather than constant. */
machine_mode pos_mode;
};
bool get_best_reg_extraction_insn (extraction_insn *,
enum extraction_pattern,
unsigned HOST_WIDE_INT, machine_mode);
bool get_best_mem_extraction_insn (extraction_insn *,
enum extraction_pattern,
HOST_WIDE_INT, HOST_WIDE_INT, machine_mode);
enum insn_code can_extend_p (machine_mode, machine_mode, int);
enum insn_code can_float_p (machine_mode, machine_mode, int);
enum insn_code can_fix_p (machine_mode, machine_mode, int, bool *);
bool can_conditionally_move_p (machine_mode mode);
bool can_vec_perm_p (machine_mode, bool, const unsigned char *);
enum insn_code widening_optab_handler (optab, machine_mode, machine_mode);
/* Find a widening optab even if it doesn't widen as much as we want. */
#define find_widening_optab_handler(A,B,C,D) \
find_widening_optab_handler_and_mode (A, B, C, D, NULL)
enum insn_code find_widening_optab_handler_and_mode (optab, machine_mode,
machine_mode, int,
machine_mode *);
int can_mult_highpart_p (machine_mode, bool);
bool can_vec_mask_load_store_p (machine_mode, bool);
bool can_compare_and_swap_p (machine_mode, bool);
bool can_atomic_exchange_p (machine_mode, bool);
bool lshift_cheap_p (bool);
#endif

370
gcc/optabs-tree.c Normal file
View File

@ -0,0 +1,370 @@
/* Tree-based target query functions relating to optabs
Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "insn-codes.h"
#include "tree.h"
#include "optabs-tree.h"
#include "stor-layout.h"
/* Return the optab used for computing the operation given by the tree code,
CODE and the tree EXP. This function is not always usable (for example, it
cannot give complete results for multiplication or division) but probably
ought to be relied on more widely throughout the expander. */
optab
optab_for_tree_code (enum tree_code code, const_tree type,
enum optab_subtype subtype)
{
bool trapv;
switch (code)
{
case BIT_AND_EXPR:
return and_optab;
case BIT_IOR_EXPR:
return ior_optab;
case BIT_NOT_EXPR:
return one_cmpl_optab;
case BIT_XOR_EXPR:
return xor_optab;
case MULT_HIGHPART_EXPR:
return TYPE_UNSIGNED (type) ? umul_highpart_optab : smul_highpart_optab;
case TRUNC_MOD_EXPR:
case CEIL_MOD_EXPR:
case FLOOR_MOD_EXPR:
case ROUND_MOD_EXPR:
return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
case RDIV_EXPR:
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
if (TYPE_SATURATING (type))
return TYPE_UNSIGNED (type) ? usdiv_optab : ssdiv_optab;
return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
case LSHIFT_EXPR:
if (TREE_CODE (type) == VECTOR_TYPE)
{
if (subtype == optab_vector)
return TYPE_SATURATING (type) ? unknown_optab : vashl_optab;
gcc_assert (subtype == optab_scalar);
}
if (TYPE_SATURATING (type))
return TYPE_UNSIGNED (type) ? usashl_optab : ssashl_optab;
return ashl_optab;
case RSHIFT_EXPR:
if (TREE_CODE (type) == VECTOR_TYPE)
{
if (subtype == optab_vector)
return TYPE_UNSIGNED (type) ? vlshr_optab : vashr_optab;
gcc_assert (subtype == optab_scalar);
}
return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
case LROTATE_EXPR:
if (TREE_CODE (type) == VECTOR_TYPE)
{
if (subtype == optab_vector)
return vrotl_optab;
gcc_assert (subtype == optab_scalar);
}
return rotl_optab;
case RROTATE_EXPR:
if (TREE_CODE (type) == VECTOR_TYPE)
{
if (subtype == optab_vector)
return vrotr_optab;
gcc_assert (subtype == optab_scalar);
}
return rotr_optab;
case MAX_EXPR:
return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
case MIN_EXPR:
return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
case REALIGN_LOAD_EXPR:
return vec_realign_load_optab;
case WIDEN_SUM_EXPR:
return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab;
case DOT_PROD_EXPR:
return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;
case SAD_EXPR:
return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
case WIDEN_MULT_PLUS_EXPR:
return (TYPE_UNSIGNED (type)
? (TYPE_SATURATING (type)
? usmadd_widen_optab : umadd_widen_optab)
: (TYPE_SATURATING (type)
? ssmadd_widen_optab : smadd_widen_optab));
case WIDEN_MULT_MINUS_EXPR:
return (TYPE_UNSIGNED (type)
? (TYPE_SATURATING (type)
? usmsub_widen_optab : umsub_widen_optab)
: (TYPE_SATURATING (type)
? ssmsub_widen_optab : smsub_widen_optab));
case FMA_EXPR:
return fma_optab;
case REDUC_MAX_EXPR:
return TYPE_UNSIGNED (type)
? reduc_umax_scal_optab : reduc_smax_scal_optab;
case REDUC_MIN_EXPR:
return TYPE_UNSIGNED (type)
? reduc_umin_scal_optab : reduc_smin_scal_optab;
case REDUC_PLUS_EXPR:
return reduc_plus_scal_optab;
case VEC_WIDEN_MULT_HI_EXPR:
return TYPE_UNSIGNED (type) ?
vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
case VEC_WIDEN_MULT_LO_EXPR:
return TYPE_UNSIGNED (type) ?
vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
case VEC_WIDEN_MULT_EVEN_EXPR:
return TYPE_UNSIGNED (type) ?
vec_widen_umult_even_optab : vec_widen_smult_even_optab;
case VEC_WIDEN_MULT_ODD_EXPR:
return TYPE_UNSIGNED (type) ?
vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
case VEC_WIDEN_LSHIFT_HI_EXPR:
return TYPE_UNSIGNED (type) ?
vec_widen_ushiftl_hi_optab : vec_widen_sshiftl_hi_optab;
case VEC_WIDEN_LSHIFT_LO_EXPR:
return TYPE_UNSIGNED (type) ?
vec_widen_ushiftl_lo_optab : vec_widen_sshiftl_lo_optab;
case VEC_UNPACK_HI_EXPR:
return TYPE_UNSIGNED (type) ?
vec_unpacku_hi_optab : vec_unpacks_hi_optab;
case VEC_UNPACK_LO_EXPR:
return TYPE_UNSIGNED (type) ?
vec_unpacku_lo_optab : vec_unpacks_lo_optab;
case VEC_UNPACK_FLOAT_HI_EXPR:
/* The signedness is determined from input operand. */
return TYPE_UNSIGNED (type) ?
vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab;
case VEC_UNPACK_FLOAT_LO_EXPR:
/* The signedness is determined from input operand. */
return TYPE_UNSIGNED (type) ?
vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab;
case VEC_PACK_TRUNC_EXPR:
return vec_pack_trunc_optab;
case VEC_PACK_SAT_EXPR:
return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
case VEC_PACK_FIX_TRUNC_EXPR:
/* The signedness is determined from output operand. */
return TYPE_UNSIGNED (type) ?
vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab;
default:
break;
}
trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
switch (code)
{
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
if (TYPE_SATURATING (type))
return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
return trapv ? addv_optab : add_optab;
case MINUS_EXPR:
if (TYPE_SATURATING (type))
return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
return trapv ? subv_optab : sub_optab;
case MULT_EXPR:
if (TYPE_SATURATING (type))
return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
return trapv ? smulv_optab : smul_optab;
case NEGATE_EXPR:
if (TYPE_SATURATING (type))
return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
return trapv ? negv_optab : neg_optab;
case ABS_EXPR:
return trapv ? absv_optab : abs_optab;
default:
return unknown_optab;
}
}
/* Given optab UNOPTAB that reduces a vector to a scalar, find instead the old
optab that produces a vector with the reduction result in one element,
for a tree with type TYPE. */
optab
scalar_reduc_to_vector (optab unoptab, const_tree type)
{
switch (unoptab)
{
case reduc_plus_scal_optab:
return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
case reduc_smin_scal_optab: return reduc_smin_optab;
case reduc_umin_scal_optab: return reduc_umin_optab;
case reduc_smax_scal_optab: return reduc_smax_optab;
case reduc_umax_scal_optab: return reduc_umax_optab;
default: return unknown_optab;
}
}
/* Function supportable_convert_operation
Check whether an operation represented by the code CODE is a
convert operation that is supported by the target platform in
vector form (i.e., when operating on arguments of type VECTYPE_IN
producing a result of type VECTYPE_OUT).
Convert operations we currently support directly are FIX_TRUNC and FLOAT.
This function checks if these operations are supported
by the target platform either directly (via vector tree-codes), or via
target builtins.
Output:
- CODE1 is code of vector operation to be used when
vectorizing the operation, if available.
- DECL is decl of target builtin functions to be used
when vectorizing the operation, if available. In this case,
CODE1 is CALL_EXPR. */
bool
supportable_convert_operation (enum tree_code code,
tree vectype_out, tree vectype_in,
tree *decl, enum tree_code *code1)
{
machine_mode m1,m2;
bool truncp;
m1 = TYPE_MODE (vectype_out);
m2 = TYPE_MODE (vectype_in);
/* First check if we can done conversion directly. */
if ((code == FIX_TRUNC_EXPR
&& can_fix_p (m1,m2,TYPE_UNSIGNED (vectype_out), &truncp)
!= CODE_FOR_nothing)
|| (code == FLOAT_EXPR
&& can_float_p (m1,m2,TYPE_UNSIGNED (vectype_in))
!= CODE_FOR_nothing))
{
*code1 = code;
return true;
}
/* Now check for builtin. */
if (targetm.vectorize.builtin_conversion
&& targetm.vectorize.builtin_conversion (code, vectype_out, vectype_in))
{
*code1 = CALL_EXPR;
*decl = targetm.vectorize.builtin_conversion (code, vectype_out,
vectype_in);
return true;
}
return false;
}
/* Return TRUE iff, appropriate vector insns are available
for vector cond expr with vector type VALUE_TYPE and a comparison
with operand vector types in CMP_OP_TYPE. */
bool
expand_vec_cond_expr_p (tree value_type, tree cmp_op_type)
{
machine_mode value_mode = TYPE_MODE (value_type);
machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
if (GET_MODE_SIZE (value_mode) != GET_MODE_SIZE (cmp_op_mode)
|| GET_MODE_NUNITS (value_mode) != GET_MODE_NUNITS (cmp_op_mode)
|| get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type),
TYPE_UNSIGNED (cmp_op_type)) == CODE_FOR_nothing)
return false;
return true;
}
/* Use the current target and options to initialize
TREE_OPTIMIZATION_OPTABS (OPTNODE). */
void
init_tree_optimization_optabs (tree optnode)
{
/* Quick exit if we have already computed optabs for this target. */
if (TREE_OPTIMIZATION_BASE_OPTABS (optnode) == this_target_optabs)
return;
/* Forget any previous information and set up for the current target. */
TREE_OPTIMIZATION_BASE_OPTABS (optnode) = this_target_optabs;
struct target_optabs *tmp_optabs = (struct target_optabs *)
TREE_OPTIMIZATION_OPTABS (optnode);
if (tmp_optabs)
memset (tmp_optabs, 0, sizeof (struct target_optabs));
else
tmp_optabs = ggc_alloc<target_optabs> ();
/* Generate a new set of optabs into tmp_optabs. */
init_all_optabs (tmp_optabs);
/* If the optabs changed, record it. */
if (memcmp (tmp_optabs, this_target_optabs, sizeof (struct target_optabs)))
TREE_OPTIMIZATION_OPTABS (optnode) = tmp_optabs;
else
{
TREE_OPTIMIZATION_OPTABS (optnode) = NULL;
ggc_free (tmp_optabs);
}
}

45
gcc/optabs-tree.h Normal file
View File

@ -0,0 +1,45 @@
/* Tree-based target query functions relating to optabs
Copyright (C) 2001-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_OPTABS_TREE_H
#define GCC_OPTABS_TREE_H
#include "optabs-query.h"
/* An extra flag to control optab_for_tree_code's behavior. This is needed to
distinguish between machines with a vector shift that takes a scalar for the
shift amount vs. machines that take a vector for the shift amount. */
enum optab_subtype
{
optab_default,
optab_scalar,
optab_vector
};
/* Return the optab used for computing the given operation on the type given by
the second argument. The third argument distinguishes between the types of
vector shifts and rotates. */
optab optab_for_tree_code (enum tree_code, const_tree, enum optab_subtype);
optab scalar_reduc_to_vector (optab, const_tree);
bool supportable_convert_operation (enum tree_code, tree, tree, tree *,
enum tree_code *);
bool expand_vec_cond_expr_p (tree, tree);
void init_tree_optimization_optabs (tree);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -20,87 +20,12 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_OPTABS_H
#define GCC_OPTABS_H
#include "insn-opinit.h"
#include "optabs-query.h"
#include "optabs-libfuncs.h"
/* Generate code for a widening multiply. */
extern rtx expand_widening_mult (machine_mode, rtx, rtx, rtx, int, optab);
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
static inline enum insn_code
optab_handler (optab op, machine_mode mode)
{
unsigned scode = (op << 16) | mode;
gcc_assert (op > LAST_CONV_OPTAB);
return raw_optab_handler (scode);
}
/* Return the insn used to perform conversion OP from mode FROM_MODE
to mode TO_MODE; return CODE_FOR_nothing if the target does not have
such an insn. */
static inline enum insn_code
convert_optab_handler (convert_optab op, machine_mode to_mode,
machine_mode from_mode)
{
unsigned scode = (op << 16) | (from_mode << 8) | to_mode;
gcc_assert (op > unknown_optab && op <= LAST_CONV_OPTAB);
return raw_optab_handler (scode);
}
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
static inline enum insn_code
direct_optab_handler (direct_optab op, machine_mode mode)
{
return optab_handler (op, mode);
}
/* Return true if UNOPTAB is for a trapping-on-overflow operation. */
static inline bool
trapv_unoptab_p (optab unoptab)
{
return (unoptab == negv_optab
|| unoptab == absv_optab);
}
/* Return true if BINOPTAB is for a trapping-on-overflow operation. */
static inline bool
trapv_binoptab_p (optab binoptab)
{
return (binoptab == addv_optab
|| binoptab == subv_optab
|| binoptab == smulv_optab);
}
/* Describes an instruction that inserts or extracts a bitfield. */
struct extraction_insn
{
/* The code of the instruction. */
enum insn_code icode;
/* The mode that the structure operand should have. This is byte_mode
when using the legacy insv, extv and extzv patterns to access memory. */
machine_mode struct_mode;
/* The mode of the field to be inserted or extracted, and by extension
the mode of the insertion or extraction itself. */
machine_mode field_mode;
/* The mode of the field's bit position. This is only important
when the position is variable rather than constant. */
machine_mode pos_mode;
};
/* Describes the type of an expand_operand. Each value is associated
with a create_*_operand function; see the comments above those
functions for details. */
@ -227,30 +152,6 @@ create_integer_operand (struct expand_operand *op, HOST_WIDE_INT intval)
}
extern rtx convert_optab_libfunc (convert_optab optab, machine_mode mode1,
machine_mode mode2);
extern rtx optab_libfunc (optab optab, machine_mode mode);
extern enum insn_code widening_optab_handler (optab, machine_mode,
machine_mode);
/* Find a widening optab even if it doesn't widen as much as we want. */
#define find_widening_optab_handler(A,B,C,D) \
find_widening_optab_handler_and_mode (A, B, C, D, NULL)
extern enum insn_code find_widening_optab_handler_and_mode (optab,
machine_mode,
machine_mode,
int,
machine_mode *);
/* An extra flag to control optab_for_tree_code's behavior. This is needed to
distinguish between machines with a vector shift that takes a scalar for the
shift amount vs. machines that take a vector for the shift amount. */
enum optab_subtype
{
optab_default,
optab_scalar,
optab_vector
};
/* Passed to expand_simple_binop and expand_binop to say which options
to try to use if the requested operation can't be open-coded on the
requisite mode. Either OPTAB_LIB or OPTAB_LIB_WIDEN says try using
@ -267,16 +168,6 @@ enum optab_methods
OPTAB_MUST_WIDEN
};
/* Return the optab used for computing the given operation on the type given by
the second argument. The third argument distinguishes between the types of
vector shifts and rotates */
extern optab optab_for_tree_code (enum tree_code, const_tree, enum optab_subtype);
/* Given an optab that reduces a vector to a scalar, find instead the old
optab that produces a vector with the reduction result in one element,
for a tree with the specified type. */
extern optab scalar_reduc_to_vector (optab, const_tree type);
extern rtx expand_widen_pattern_expr (struct separate_ops *, rtx , rtx , rtx,
rtx, int);
extern rtx expand_ternary_op (machine_mode mode, optab ternary_optab,
@ -368,9 +259,6 @@ extern void emit_indirect_jump (rtx);
rtx emit_conditional_move (rtx, enum rtx_code, rtx, rtx, machine_mode,
rtx, rtx, machine_mode, int);
/* Return nonzero if the conditional move is supported. */
int can_conditionally_move_p (machine_mode mode);
rtx emit_conditional_add (rtx, enum rtx_code, rtx, rtx, machine_mode,
rtx, rtx, machine_mode, int);
@ -386,22 +274,10 @@ extern rtx_insn *gen_sub2_insn (rtx, rtx);
extern rtx_insn *gen_sub3_insn (rtx, rtx, rtx);
extern int have_sub2_insn (rtx, rtx);
/* Return the INSN_CODE to use for an extend operation. */
extern enum insn_code can_extend_p (machine_mode, machine_mode, int);
/* Generate the body of an insn to extend Y (with mode MFROM)
into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */
extern rtx_insn *gen_extend_insn (rtx, rtx, machine_mode, machine_mode, int);
/* Return the insn_code for a FLOAT_EXPR. */
enum insn_code can_float_p (machine_mode, machine_mode, int);
/* Check whether an operation represented by the code CODE is a
convert operation that is supported by the target platform in
vector form */
bool supportable_convert_operation (enum tree_code, tree, tree, tree *,
enum tree_code *);
/* Generate code for a FLOAT_EXPR. */
extern void expand_float (rtx, rtx, int);
@ -418,104 +294,18 @@ extern bool expand_sfix_optab (rtx, rtx, convert_optab);
perform the operation described by CODE and MODE. */
extern int have_insn_for (enum rtx_code, machine_mode);
extern void gen_int_libfunc (optab, const char *, char, machine_mode);
extern void gen_fp_libfunc (optab, const char *, char, machine_mode);
extern void gen_fixed_libfunc (optab, const char *, char, machine_mode);
extern void gen_signed_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_unsigned_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_int_fp_libfunc (optab, const char *, char, machine_mode);
extern void gen_intv_fp_libfunc (optab, const char *, char, machine_mode);
extern void gen_int_fp_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_int_fp_signed_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_int_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_int_signed_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_int_unsigned_fixed_libfunc (optab, const char *, char,
machine_mode);
extern void gen_interclass_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_int_to_fp_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_ufloat_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_int_to_fp_nondecimal_conv_libfunc (convert_optab,
const char *,
machine_mode,
machine_mode);
extern void gen_fp_to_int_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_intraclass_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_trunc_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_extend_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_fract_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_fractuns_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_satfract_conv_libfunc (convert_optab, const char *,
machine_mode, machine_mode);
extern void gen_satfractuns_conv_libfunc (convert_optab, const char *,
machine_mode,
machine_mode);
/* Build a decl for a libfunc named NAME. */
extern tree build_libfunc_function (const char *);
/* Call this to initialize an optab function entry. */
extern rtx init_one_libfunc (const char *);
extern rtx set_user_assembler_libfunc (const char *, const char *);
/* Call this to reset the function entry for one optab. */
extern void set_optab_libfunc (optab, machine_mode, const char *);
extern void set_conv_libfunc (convert_optab, machine_mode,
machine_mode, const char *);
/* Call this once to initialize the contents of the optabs
appropriately for the current target machine. */
extern void init_optabs (void);
extern void init_tree_optimization_optabs (tree);
/* Call this to install all of the __sync libcalls up to size MAX. */
extern void init_sync_libfuncs (int max);
/* Generate a conditional trap instruction. */
extern rtx_insn *gen_cond_trap (enum rtx_code, rtx, rtx, rtx);
/* Return true if target supports vector operations for VEC_PERM_EXPR. */
extern bool can_vec_perm_p (machine_mode, bool, const unsigned char *);
/* Generate code for VEC_PERM_EXPR. */
extern rtx expand_vec_perm (machine_mode, rtx, rtx, rtx, rtx);
/* Return tree if target supports vector operations for COND_EXPR. */
bool expand_vec_cond_expr_p (tree, tree);
/* Generate code for VEC_COND_EXPR. */
extern rtx expand_vec_cond_expr (tree, tree, tree, tree, rtx);
/* Return non-zero if target supports a given highpart multiplication. */
extern int can_mult_highpart_p (machine_mode, bool);
/* Generate code for MULT_HIGHPART_EXPR. */
extern rtx expand_mult_highpart (machine_mode, rtx, rtx, rtx, bool);
/* Return true if target supports vector masked load/store for mode. */
extern bool can_vec_mask_load_store_p (machine_mode, bool);
/* Return true if there is an inline compare and swap pattern. */
extern bool can_compare_and_swap_p (machine_mode, bool);
/* Return true if there is an inline atomic exchange pattern. */
extern bool can_atomic_exchange_p (machine_mode, bool);
extern rtx expand_sync_lock_test_and_set (rtx, rtx, rtx);
extern rtx expand_atomic_test_and_set (rtx, rtx, enum memmodel);
extern rtx expand_atomic_exchange (rtx, rtx, rtx, enum memmodel);
@ -549,20 +339,6 @@ extern void expand_insn (enum insn_code icode, unsigned int nops,
extern void expand_jump_insn (enum insn_code icode, unsigned int nops,
struct expand_operand *ops);
/* Enumerates the possible extraction_insn operations. */
enum extraction_pattern { EP_insv, EP_extv, EP_extzv };
extern bool get_best_reg_extraction_insn (extraction_insn *,
enum extraction_pattern,
unsigned HOST_WIDE_INT,
machine_mode);
extern bool get_best_mem_extraction_insn (extraction_insn *,
enum extraction_pattern,
HOST_WIDE_INT, HOST_WIDE_INT,
machine_mode);
extern bool lshift_cheap_p (bool);
extern enum rtx_code get_rtx_code (enum tree_code tcode, bool unsignedp);
#endif /* GCC_OPTABS_H */

View File

@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-query.h"
#include "libfuncs.h"
#include "cfgloop.h"
#include "ira.h"

View File

@ -87,7 +87,8 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-prop.h"
#include "gcse.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-query.h"
#include "optabs-libfuncs.h"
#include "tree-chkp.h"
#include "omp-low.h"

View File

@ -120,7 +120,7 @@ along with GCC; see the file COPYING3. If not see
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-query.h"
#include "tree-hash-traits.h"
/* List of basic blocks in if-conversion-suitable order. */

View File

@ -54,7 +54,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "cfgloop.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-query.h"
#include "tree-ssa-propagate.h"
#include "tree-ssa-dom.h"
#include "builtins.h"

View File

@ -65,7 +65,7 @@ along with GCC; see the file COPYING3. If not see
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-query.h"
#include "recog.h"
/* This pass inserts prefetch instructions to optimize cache usage during

View File

@ -103,15 +103,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify-me.h"
#include "stor-layout.h"
#include "tree-cfg.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "tree-dfa.h"
#include "tree-ssa.h"
#include "tree-pass.h"
@ -120,11 +111,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "builtins.h"
#include "params.h"
/* FIXME: RTL headers have to be included here for optabs. */
#include "expr.h" /* Because optabs.h wants sepops. */
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
/* This structure represents one basic block that either computes a
division, or is a common dominator for basic block that compute a

View File

@ -38,14 +38,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify-me.h"
#include "tree-cfg.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "tree-dfa.h"
#include "tree-pass.h"
#include "langhooks.h"
@ -54,7 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-data-ref.h"
#include "gimple-pretty-print.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "tree-scalar-evolution.h"
#include "tree-inline.h"
#include "params.h"

View File

@ -43,15 +43,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-loop-niter.h"
#include "tree-ssa-loop.h"
#include "flags.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "tree-dfa.h"
#include "tree-ssa.h"
#include "tree-iterator.h"
@ -65,7 +56,7 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "gimplify.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
/* This is a simple global reassociation pass. It is, in part, based
on the LLVM pass of the same name (They do some things more/less

View File

@ -52,17 +52,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
type in the GIMPLE type system that is language-independent? */
#include "langhooks.h"
/* Need to include expr.h and optabs.h for lshift_cheap_p. */
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
/* Maximum number of case bit tests.
FIXME: This should be derived from PARAM_CASE_VALUES_THRESHOLD and

View File

@ -49,19 +49,9 @@ along with GCC; see the file COPYING3. If not see
#include "tree-vectorizer.h"
#include "diagnostic-core.h"
#include "cgraph.h"
/* Need to include rtl.h, expr.h, etc. for optabs. */
#include "flags.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "builtins.h"
#include "params.h"

View File

@ -40,19 +40,9 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "diagnostic.h"
#include "target.h"
/* Need to include rtl.h, expr.h, etc. for optabs. */
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
static void expand_vector_operations_1 (gimple_stmt_iterator *);

View File

@ -44,18 +44,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h"
#include "cfgloop.h"
#include "flags.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "recog.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "params.h"
#include "diagnostic-core.h"
#include "tree-chrec.h"

View File

@ -40,15 +40,8 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "params.h"
#include "tree-data-ref.h"
#include "tree-vectorizer.h"

View File

@ -40,17 +40,9 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "flags.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "recog.h" /* FIXME: for insn_data */
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "tree-vectorizer.h"
#include "langhooks.h"
#include "gimple-walk.h"

View File

@ -45,17 +45,9 @@ along with GCC; see the file COPYING3. If not see
#include "tree-scalar-evolution.h"
#include "flags.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "recog.h" /* FIXME: for insn_data */
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "diagnostic-core.h"
#include "tree-vectorizer.h"
#include "cgraph.h"

View File

@ -54,16 +54,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-propagate.h"
#include "tree-chrec.h"
#include "tree-ssa-threadupdate.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "insn-codes.h"
#include "optabs.h"
#include "optabs-tree.h"
#include "tree-ssa-scopedtables.h"
#include "tree-ssa-threadedge.h"