From patchwork Mon Sep 14 17:54:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 517513 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C8F4D140497 for ; Tue, 15 Sep 2015 03:55:02 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=p9gbC5P8; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=Ia5BRNLz0+OpDe+d 8XQ9DWvS6dggzAtnQ8pIfC0xRt6FCsW0Hph9OniSZwcZUCBXyQzPQWdNYcdiujGF v3r2WBTilh8eZJIGRFPZtuc9FgBQ5BOU56xBlGvfr4AhCPRGAiufSH7y7MOJAn9Q KvZ4ZoZRpL89jr7qoDZ5TkkkVbk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; s=default; bh=k6bn64E8rzjVq3RT02ykmh eQY88=; b=p9gbC5P8QreQqC1L+gtRjBki0sHU2LXmwMTtXTV0xNBWm5TVVpIul/ Lc1sV+NnhQca9/DqaaecIleH8a9jDavS5D16LOQNGM/ueWnlLzrXPIVbIvCmygNO oTmZvPW5xVZZfNAJ3TaIEsrIufBj+gDUazK+JU/EZAixeAscm1wFY= Received: (qmail 52795 invoked by alias); 14 Sep 2015 17:54:50 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 51518 invoked by uid 89); 14 Sep 2015 17:54:49 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.7 required=5.0 tests=AWL, BAYES_50, KAM_STOCKGEN, LIKELY_SPAM_BODY, SPF_PASS autolearn=no version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (207.82.80.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 14 Sep 2015 17:54:25 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-14-DQ5Y3UIRShC7c5HLdp6pCQ-1; Mon, 14 Sep 2015 18:54:19 +0100 Received: from localhost ([10.1.2.79]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 14 Sep 2015 18:54:19 +0100 From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: Split up optabs.[hc] Date: Mon, 14 Sep 2015 18:54:18 +0100 Message-ID: <87vbbc28fp.fsf@e105548-lin.cambridge.arm.com> User-Agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-MC-Unique: DQ5Y3UIRShC7c5HLdp6pCQ-1 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. Tested on x86_64-linux-gnu, arm-linux-gnueabi and aarch64-linux-gnu. Also tested by building one cross compiler for each target directory. OK to install? Thanks, Richard 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. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b495bd2..806188f 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 \ diff --git a/gcc/cilk-common.c b/gcc/cilk-common.c index d8340b2..62acc18 100644 --- a/gcc/cilk-common.c +++ b/gcc/cilk-common.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" diff --git a/gcc/expr.c b/gcc/expr.c index cf28f44..165b016 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -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" diff --git a/gcc/fold-const.c b/gcc/fold-const.c index e9366e2..aafea16 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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 diff --git a/gcc/function.c b/gcc/function.c index 2c5a6d4..bf584be 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -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" diff --git a/gcc/genopinit.c b/gcc/genopinit.c index 77e81f5..167815d 100644 --- a/gcc/genopinit.c +++ b/gcc/genopinit.c @@ -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); } diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c new file mode 100644 index 0000000..bace520 --- /dev/null +++ b/gcc/optabs-libfuncs.c @@ -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 +. */ + + +#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 +{ + 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_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::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 (); + (*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 (); + (*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::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" diff --git a/gcc/optabs-libfuncs.h b/gcc/optabs-libfuncs.h new file mode 100644 index 0000000..4e43c80 --- /dev/null +++ b/gcc/optabs-libfuncs.h @@ -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 +. */ + +#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 diff --git a/gcc/optabs-query.c b/gcc/optabs-query.c new file mode 100644 index 0000000..254089f --- /dev/null +++ b/gcc/optabs-query.c @@ -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 +. */ + + +#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]; +} diff --git a/gcc/optabs-query.h b/gcc/optabs-query.h new file mode 100644 index 0000000..73f2729 --- /dev/null +++ b/gcc/optabs-query.h @@ -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 +. */ + +#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 diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c new file mode 100644 index 0000000..3b03338 --- /dev/null +++ b/gcc/optabs-tree.c @@ -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 +. */ + + +#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 (); + + /* 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); + } +} diff --git a/gcc/optabs-tree.h b/gcc/optabs-tree.h new file mode 100644 index 0000000..bf6c9e3 --- /dev/null +++ b/gcc/optabs-tree.h @@ -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 +. */ + +#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 diff --git a/gcc/optabs.c b/gcc/optabs.c index 79c6f06..b7857a5 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -33,8 +33,6 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "tree-hasher.h" #include "stor-layout.h" -#include "stringpool.h" -#include "varasm.h" #include "tm_p.h" #include "flags.h" #include "except.h" @@ -47,22 +45,12 @@ along with GCC; see the file COPYING3. If not see #include "expr.h" #include "insn-codes.h" #include "optabs.h" +#include "optabs-tree.h" #include "libfuncs.h" #include "recog.h" #include "reload.h" #include "target.h" -struct target_optabs default_target_optabs; -struct target_libfuncs default_target_libfuncs; -struct target_optabs *this_fn_optabs = &default_target_optabs; -#if SWITCHABLE_TARGET -struct target_optabs *this_target_optabs = &default_target_optabs; -struct target_libfuncs *this_target_libfuncs = &default_target_libfuncs; -#endif - -#define libfunc_hash \ - (this_target_libfuncs->x_libfunc_hash) - static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *, machine_mode *); static rtx expand_unop_direct (machine_mode, optab, rtx, rtx, int); @@ -70,101 +58,6 @@ static void emit_libcall_block_1 (rtx_insn *, rtx, rtx, rtx, bool); /* Debug facility for use in GDB. */ void debug_optab_libfuncs (void); - -/* 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; -} - /* Add a REG_EQUAL note to the last insn in INSNS. TARGET is being set to the result of operation CODE applied to OP0 (and OP1 if it is a binary @@ -298,56 +191,6 @@ widened_mode (machine_mode to_mode, rtx op0, rtx op1) return result; } -/* 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; -} - /* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need not actually do a sign-extend or zero-extend, but can leave the @@ -386,245 +229,6 @@ widen_operand (rtx op, machine_mode mode, machine_mode oldmode, return result; } -/* 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; - } -} - /* Expand vector widening operations. There are two different classes of operations handled here: @@ -4606,23 +4210,6 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, return NULL_RTX; } -/* 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? */ - -int -can_conditionally_move_p (machine_mode mode) -{ - if (direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing) - return 1; - - return 0; -} - /* Emit a conditional addition instruction if the machine supports one for that condition and machine mode. @@ -4853,22 +4440,6 @@ have_sub2_insn (rtx x, rtx y) return 1; } -/* 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) -{ - convert_optab tab; - if (unsignedp < 0 && targetm.have_ptr_extend ()) - return targetm.code_for_ptr_extend; - - tab = unsignedp ? zext_optab : sext_optab; - return convert_optab_handler (tab, to_mode, from_mode); -} - /* Generate the body of an insn to extend Y (with mode MFROM) into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ @@ -4880,110 +4451,6 @@ gen_extend_insn (rtx x, rtx y, machine_mode mto, return GEN_FCN (icode) (x, y); } -/* can_fix_p and can_float_p say whether the target machine - can directly convert a given fixed point type to - a given floating point type, or vice versa. - The returned value is the CODE_FOR_... value to use, - or CODE_FOR_nothing if these modes cannot be directly converted. - - *TRUNCP_PTR is set to 1 if it is necessary to output - an explicit FTRUNC insn before the fix insn; otherwise 0. */ - -static enum insn_code -can_fix_p (machine_mode fixmode, machine_mode fltmode, - int unsignedp, int *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 = 0; - 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 = 1; - return icode; - } - - *truncp_ptr = 0; - return CODE_FOR_nothing; -} - -enum insn_code -can_float_p (machine_mode fltmode, machine_mode fixmode, - int unsignedp) -{ - convert_optab tab; - - tab = unsignedp ? ufloat_optab : sfloat_optab; - return convert_optab_handler (tab, fltmode, fixmode); -} - -/* 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; - int 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; -} - - /* Generate code to convert FROM to floating point and store in TO. FROM must be fixed point and not VOIDmode. UNSIGNEDP nonzero means regard FROM as unsigned. @@ -5197,7 +4664,7 @@ expand_fix (rtx to, rtx from, int unsignedp) enum insn_code icode; rtx target = to; machine_mode fmode, imode; - int must_trunc = 0; + bool must_trunc = false; /* We first try to find a pair of modes, one real and one integer, at least as wide as FROM and TO, respectively, in which we can open-code @@ -5478,957 +4945,91 @@ have_insn_for (enum rtx_code code, machine_mode mode) != CODE_FOR_nothing)); } -/* 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. -*/ +/* Print information about the current contents of the optabs on + STDERR. */ -static void -gen_libfunc (optab optable, const char *opname, int suffix, - machine_mode mode) +DEBUG_FUNCTION void +debug_optab_libfuncs (void) { - 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)); + int i, j, k; + + /* Dump the arithmetic optabs. */ + for (i = FIRST_NORM_OPTAB; i <= LAST_NORMLIB_OPTAB; ++i) + for (j = 0; j < NUM_MACHINE_MODES; ++j) + { + rtx l = optab_libfunc ((optab) i, (machine_mode) j); + if (l) + { + gcc_assert (GET_CODE (l) == SYMBOL_REF); + fprintf (stderr, "%s\t%s:\t%s\n", + GET_RTX_NAME (optab_to_code ((optab) i)), + GET_MODE_NAME (j), + XSTR (l, 0)); + } + } + + /* Dump the conversion optabs. */ + for (i = FIRST_CONV_OPTAB; i <= LAST_CONVLIB_OPTAB; ++i) + for (j = 0; j < NUM_MACHINE_MODES; ++j) + for (k = 0; k < NUM_MACHINE_MODES; ++k) + { + rtx l = convert_optab_libfunc ((optab) i, (machine_mode) j, + (machine_mode) k); + if (l) + { + gcc_assert (GET_CODE (l) == SYMBOL_REF); + fprintf (stderr, "%s\t%s\t%s:\t%s\n", + GET_RTX_NAME (optab_to_code ((optab) i)), + GET_MODE_NAME (j), + GET_MODE_NAME (k), + XSTR (l, 0)); + } + } } -/* Like gen_libfunc, but verify that integer operation is involved. */ +/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition + CODE. Return 0 on failure. */ -void -gen_int_libfunc (optab optable, const char *opname, char suffix, - machine_mode mode) +rtx_insn * +gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, rtx tcode) { - int maxsize = 2 * BITS_PER_WORD; - int minsize = BITS_PER_WORD; + machine_mode mode = GET_MODE (op1); + enum insn_code icode; + rtx_insn *insn; + rtx trap_rtx; - 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); -} + if (mode == VOIDmode) + return 0; + + icode = optab_handler (ctrap_optab, mode); + if (icode == CODE_FOR_nothing) + return 0; -/* Like gen_libfunc, but verify that FP and set decimal prefix if needed. */ + /* Some targets only accept a zero trap code. */ + if (!insn_operand_matches (icode, 3, tcode)) + return 0; -void -gen_fp_libfunc (optab optable, const char *opname, char suffix, - machine_mode mode) -{ - char *dec_opname; + do_pending_stack_adjust (); + start_sequence (); + prepare_cmp_insn (op1, op2, code, NULL_RTX, false, OPTAB_DIRECT, + &trap_rtx, &mode); + if (!trap_rtx) + insn = NULL; + else + insn = GEN_FCN (icode) (trap_rtx, XEXP (trap_rtx, 0), XEXP (trap_rtx, 1), + tcode); - if (GET_MODE_CLASS (mode) == MODE_FLOAT) - gen_libfunc (optable, opname, suffix, mode); - if (DECIMAL_FLOAT_MODE_P (mode)) + /* If that failed, then give up. */ + if (insn == 0) { - 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); + end_sequence (); + return 0; } -} - -/* 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 -{ - 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_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; -} - -rtx -init_one_libfunc (const char *name) -{ - tree id, decl; - hashval_t hash; - - if (libfunc_decls == NULL) - libfunc_decls = hash_table::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 (); - (*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 (); - (*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::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 (); -} - -/* 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 (); - - /* 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); - } -} - -/* 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); -} - -/* Print information about the current contents of the optabs on - STDERR. */ - -DEBUG_FUNCTION void -debug_optab_libfuncs (void) -{ - int i, j, k; - - /* Dump the arithmetic optabs. */ - for (i = FIRST_NORM_OPTAB; i <= LAST_NORMLIB_OPTAB; ++i) - for (j = 0; j < NUM_MACHINE_MODES; ++j) - { - rtx l = optab_libfunc ((optab) i, (machine_mode) j); - if (l) - { - gcc_assert (GET_CODE (l) == SYMBOL_REF); - fprintf (stderr, "%s\t%s:\t%s\n", - GET_RTX_NAME (optab_to_code ((optab) i)), - GET_MODE_NAME (j), - XSTR (l, 0)); - } - } - - /* Dump the conversion optabs. */ - for (i = FIRST_CONV_OPTAB; i <= LAST_CONVLIB_OPTAB; ++i) - for (j = 0; j < NUM_MACHINE_MODES; ++j) - for (k = 0; k < NUM_MACHINE_MODES; ++k) - { - rtx l = convert_optab_libfunc ((optab) i, (machine_mode) j, - (machine_mode) k); - if (l) - { - gcc_assert (GET_CODE (l) == SYMBOL_REF); - fprintf (stderr, "%s\t%s\t%s:\t%s\n", - GET_RTX_NAME (optab_to_code ((optab) i)), - GET_MODE_NAME (j), - GET_MODE_NAME (k), - XSTR (l, 0)); - } - } -} - - -/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition - CODE. Return 0 on failure. */ - -rtx_insn * -gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, rtx tcode) -{ - machine_mode mode = GET_MODE (op1); - enum insn_code icode; - rtx_insn *insn; - rtx trap_rtx; - - if (mode == VOIDmode) - return 0; - - icode = optab_handler (ctrap_optab, mode); - if (icode == CODE_FOR_nothing) - return 0; - - /* Some targets only accept a zero trap code. */ - if (!insn_operand_matches (icode, 3, tcode)) - return 0; - - do_pending_stack_adjust (); - start_sequence (); - prepare_cmp_insn (op1, op2, code, NULL_RTX, false, OPTAB_DIRECT, - &trap_rtx, &mode); - if (!trap_rtx) - insn = NULL; - else - insn = GEN_FCN (icode) (trap_rtx, XEXP (trap_rtx, 0), XEXP (trap_rtx, 1), - tcode); - - /* If that failed, then give up. */ - if (insn == 0) - { - end_sequence (); - return 0; - } - - emit_insn (insn); - insn = get_insns (); - end_sequence (); - return insn; + + emit_insn (insn); + insn = get_insns (); + end_sequence (); + return insn; } /* Return rtx code for TCODE. Use UNSIGNEDP to select signed @@ -6534,63 +5135,6 @@ vector_compare_rtx (enum tree_code tcode, tree t_op0, tree t_op1, return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value); } -/* 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; -} - /* Checks if vec_perm mask SEL is a constant equivalent to a shift of the first vec_perm operand, assuming the second operand is a constant vector of zeroes. Return the shift distance in bits if so, or NULL_RTX if the vec_perm is not a @@ -6800,37 +5344,6 @@ expand_vec_perm (machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target) return tmp; } -/* 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. */ - -static 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; -} - -/* 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; -} - /* Generate insns for a VEC_COND_EXPR, given its TYPE and its three operands. */ @@ -6886,57 +5399,6 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2, return ops[0].value; } -/* 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; -} - /* Expand a highpart multiply. */ rtx @@ -7008,89 +5470,7 @@ expand_mult_highpart (machine_mode mode, rtx op0, rtx op1, return expand_vec_perm (mode, m1, m2, perm, target); } - -/* 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); -} - - /* Helper function to find the MODE_CC set in a sync_compare_and_swap pattern. */ @@ -8411,225 +6791,3 @@ expand_jump_insn (enum insn_code icode, unsigned int nops, if (!maybe_expand_jump_insn (icode, nops, ops)) gcc_unreachable (); } - -/* Reduce conditional compilation elsewhere. */ - -/* 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); -} - -/* 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]; -} - -#include "gt-optabs.h" diff --git a/gcc/optabs.h b/gcc/optabs.h index 95f5cbc..3f29d1b 100644 --- a/gcc/optabs.h +++ b/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 */ diff --git a/gcc/target-globals.c b/gcc/target-globals.c index 654a059..54b8517 100644 --- a/gcc/target-globals.c +++ b/gcc/target-globals.c @@ -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" diff --git a/gcc/toplev.c b/gcc/toplev.c index 926224a..68479e6 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -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" diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 291e602..0987884 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -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. */ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index ccfde5f..5978c59 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -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" diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c index 1adaed5..0260b26 100644 --- a/gcc/tree-ssa-loop-prefetch.c +++ b/gcc/tree-ssa-loop-prefetch.c @@ -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 diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index eae5358..b1cc42e 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -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 diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index d46ba62..0c0a393 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -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" diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 45e7b61..7d3b691 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -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 diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c index 3201912..4208140 100644 --- a/gcc/tree-switch-conversion.c +++ b/gcc/tree-switch-conversion.c @@ -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 diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index 2439bd6..671e613 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -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" diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index be3d27f..68a7b74 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -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 *); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 59c75af..c095317 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -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" diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 758ca38..b0aae4f 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -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" diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index 2face16..1dd8167 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -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" diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 359e010..d4a436d 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -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" diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index d7615e1..882f84d 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -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"