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:
parent
a78eb72ac0
commit
385399a875
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
974
gcc/optabs-libfuncs.c
Normal 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
77
gcc/optabs-libfuncs.h
Normal 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
573
gcc/optabs-query.c
Normal 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
138
gcc/optabs-query.h
Normal 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
370
gcc/optabs-tree.c
Normal 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
45
gcc/optabs-tree.h
Normal 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
|
1846
gcc/optabs.c
1846
gcc/optabs.c
File diff suppressed because it is too large
Load Diff
228
gcc/optabs.h
228
gcc/optabs.h
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user