/* Copyright (C) 1988-2022 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
. */
#define IN_TARGET_CODE 1
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "rtl.h"
#include "tree.h"
#include "memmodel.h"
#include "gimple.h"
#include "cfghooks.h"
#include "cfgloop.h"
#include "df.h"
#include "tm_p.h"
#include "stringpool.h"
#include "expmed.h"
#include "optabs.h"
#include "regs.h"
#include "emit-rtl.h"
#include "recog.h"
#include "cgraph.h"
#include "diagnostic.h"
#include "cfgbuild.h"
#include "alias.h"
#include "fold-const.h"
#include "attribs.h"
#include "calls.h"
#include "stor-layout.h"
#include "varasm.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "except.h"
#include "explow.h"
#include "expr.h"
#include "cfgrtl.h"
#include "common/common-target.h"
#include "langhooks.h"
#include "reload.h"
#include "gimplify.h"
#include "dwarf2.h"
#include "tm-constrs.h"
#include "cselib.h"
#include "sched-int.h"
#include "opts.h"
#include "tree-pass.h"
#include "context.h"
#include "pass_manager.h"
#include "target-globals.h"
#include "gimple-iterator.h"
#include "tree-vectorizer.h"
#include "shrink-wrap.h"
#include "builtins.h"
#include "rtl-iter.h"
#include "tree-iterator.h"
#include "dbgcnt.h"
#include "case-cfn-macros.h"
#include "dojump.h"
#include "fold-const-call.h"
#include "tree-vrp.h"
#include "tree-ssanames.h"
#include "selftest.h"
#include "selftest-rtl.h"
#include "print-rtl.h"
#include "intl.h"
#include "ifcvt.h"
#include "symbol-summary.h"
#include "ipa-prop.h"
#include "ipa-fnsummary.h"
#include "wide-int-bitmask.h"
#include "tree-vector-builder.h"
#include "debug.h"
#include "dwarf2out.h"
#include "i386-builtins.h"
#include "common/config/i386/i386-isas.h"
#undef BDESC
#undef BDESC_FIRST
#undef BDESC_END
/* Macros for verification of enum ix86_builtins order. */
#define BDESC_VERIFY(x, y, z) \
gcc_checking_assert ((x) == (enum ix86_builtins) ((y) + (z)))
#define BDESC_VERIFYS(x, y, z) \
STATIC_ASSERT ((x) == (enum ix86_builtins) ((y) + (z)))
BDESC_VERIFYS (IX86_BUILTIN__BDESC_PCMPESTR_FIRST,
IX86_BUILTIN__BDESC_COMI_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_PCMPISTR_FIRST,
IX86_BUILTIN__BDESC_PCMPESTR_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_SPECIAL_ARGS_FIRST,
IX86_BUILTIN__BDESC_PCMPISTR_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_PURE_ARGS_FIRST,
IX86_BUILTIN__BDESC_SPECIAL_ARGS_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_ARGS_FIRST,
IX86_BUILTIN__BDESC_PURE_ARGS_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_ROUND_ARGS_FIRST,
IX86_BUILTIN__BDESC_ARGS_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_MULTI_ARG_FIRST,
IX86_BUILTIN__BDESC_ROUND_ARGS_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_FIRST,
IX86_BUILTIN__BDESC_MULTI_ARG_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN_MAX,
IX86_BUILTIN__BDESC_CET_LAST, 1);
/* Table for the ix86 builtin non-function types. */
static GTY(()) tree ix86_builtin_type_tab[(int) IX86_BT_LAST_CPTR + 1];
tree ix86_float16_type_node = NULL_TREE;
/* Retrieve an element from the above table, building some of
the types lazily. */
static tree
ix86_get_builtin_type (enum ix86_builtin_type tcode)
{
unsigned int index;
tree type, itype;
gcc_assert ((unsigned)tcode < ARRAY_SIZE(ix86_builtin_type_tab));
type = ix86_builtin_type_tab[(int) tcode];
if (type != NULL)
return type;
gcc_assert (tcode > IX86_BT_LAST_PRIM);
if (tcode <= IX86_BT_LAST_VECT)
{
machine_mode mode;
index = tcode - IX86_BT_LAST_PRIM - 1;
itype = ix86_get_builtin_type (ix86_builtin_type_vect_base[index]);
mode = ix86_builtin_type_vect_mode[index];
type = build_vector_type_for_mode (itype, mode);
}
else
{
int quals;
index = tcode - IX86_BT_LAST_VECT - 1;
if (tcode <= IX86_BT_LAST_PTR)
quals = TYPE_UNQUALIFIED;
else
quals = TYPE_QUAL_CONST;
itype = ix86_get_builtin_type (ix86_builtin_type_ptr_base[index]);
if (quals != TYPE_UNQUALIFIED)
itype = build_qualified_type (itype, quals);
type = build_pointer_type (itype);
}
ix86_builtin_type_tab[(int) tcode] = type;
return type;
}
/* Table for the ix86 builtin function types. */
static GTY(()) tree ix86_builtin_func_type_tab[(int) IX86_BT_LAST_ALIAS + 1];
/* Retrieve an element from the above table, building some of
the types lazily. */
static tree
ix86_get_builtin_func_type (enum ix86_builtin_func_type tcode)
{
tree type;
gcc_assert ((unsigned)tcode < ARRAY_SIZE (ix86_builtin_func_type_tab));
type = ix86_builtin_func_type_tab[(int) tcode];
if (type != NULL)
return type;
if (tcode <= IX86_BT_LAST_FUNC)
{
unsigned start = ix86_builtin_func_start[(int) tcode];
unsigned after = ix86_builtin_func_start[(int) tcode + 1];
tree rtype, atype, args = void_list_node;
unsigned i;
rtype = ix86_get_builtin_type (ix86_builtin_func_args[start]);
for (i = after - 1; i > start; --i)
{
atype = ix86_get_builtin_type (ix86_builtin_func_args[i]);
args = tree_cons (NULL, atype, args);
}
type = build_function_type (rtype, args);
}
else
{
unsigned index = tcode - IX86_BT_LAST_FUNC - 1;
enum ix86_builtin_func_type icode;
icode = ix86_builtin_func_alias_base[index];
type = ix86_get_builtin_func_type (icode);
}
ix86_builtin_func_type_tab[(int) tcode] = type;
return type;
}
/* Table for the ix86 builtin decls. */
static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX];
struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX];
tree get_ix86_builtin (enum ix86_builtins c)
{
return ix86_builtins[c];
}
/* Bits that can still enable any inclusion of a builtin. */
HOST_WIDE_INT deferred_isa_values = 0;
HOST_WIDE_INT deferred_isa_values2 = 0;
/* Add an ix86 target builtin function with CODE, NAME and TYPE. Save the
MASK and MASK2 of which isa_flags and ix86_isa_flags2 to use in the
ix86_builtins_isa array. Stores the function decl in the ix86_builtins
array. Returns the function decl or NULL_TREE, if the builtin was not
added.
If the front end has a special hook for builtin functions, delay adding
builtin functions that aren't in the current ISA until the ISA is changed
with function specific optimization. Doing so, can save about 300K for the
default compiler. When the builtin is expanded, check at that time whether
it is valid.
If the front end doesn't have a special hook, record all builtins, even if
it isn't an instruction set in the current ISA in case the user uses
function specific options for a different ISA, so that we don't get scope
errors if a builtin is added in the middle of a function scope. */
static inline tree
def_builtin (HOST_WIDE_INT mask, HOST_WIDE_INT mask2,
const char *name,
enum ix86_builtin_func_type tcode,
enum ix86_builtins code)
{
tree decl = NULL_TREE;
/* An instruction may be 64bit only regardless of ISAs. */
if (!(mask & OPTION_MASK_ISA_64BIT) || TARGET_64BIT)
{
ix86_builtins_isa[(int) code].isa = mask;
ix86_builtins_isa[(int) code].isa2 = mask2;
mask &= ~OPTION_MASK_ISA_64BIT;
/* Filter out the masks most often ored together with others. */
if ((mask & ix86_isa_flags & OPTION_MASK_ISA_AVX512VL)
&& mask != OPTION_MASK_ISA_AVX512VL)
mask &= ~OPTION_MASK_ISA_AVX512VL;
if ((mask & ix86_isa_flags & OPTION_MASK_ISA_AVX512BW)
&& mask != OPTION_MASK_ISA_AVX512BW)
mask &= ~OPTION_MASK_ISA_AVX512BW;
if (((mask2 == 0 || (mask2 & ix86_isa_flags2) != 0)
&& (mask == 0 || (mask & ix86_isa_flags) != 0))
|| ((mask & OPTION_MASK_ISA_MMX) != 0 && TARGET_MMX_WITH_SSE)
/* "Unified" builtin used by either AVXVNNI intrinsics or AVX512VNNIVL
non-mask intrinsics should be defined whenever avxvnni
or avx512vnni && avx512vl exist. */
|| (mask2 == OPTION_MASK_ISA2_AVXVNNI)
|| (lang_hooks.builtin_function
== lang_hooks.builtin_function_ext_scope))
{
tree type = ix86_get_builtin_func_type (tcode);
decl = add_builtin_function (name, type, code, BUILT_IN_MD,
NULL, NULL_TREE);
ix86_builtins[(int) code] = decl;
ix86_builtins_isa[(int) code].set_and_not_built_p = false;
}
else
{
/* Just MASK and MASK2 where set_and_not_built_p == true can potentially
include a builtin. */
deferred_isa_values |= mask;
deferred_isa_values2 |= mask2;
ix86_builtins[(int) code] = NULL_TREE;
ix86_builtins_isa[(int) code].tcode = tcode;
ix86_builtins_isa[(int) code].name = name;
ix86_builtins_isa[(int) code].const_p = false;
ix86_builtins_isa[(int) code].pure_p = false;
ix86_builtins_isa[(int) code].set_and_not_built_p = true;
}
}
return decl;
}
/* Like def_builtin, but also marks the function decl "const". */
static inline tree
def_builtin_const (HOST_WIDE_INT mask, HOST_WIDE_INT mask2, const char *name,
enum ix86_builtin_func_type tcode, enum ix86_builtins code)
{
tree decl = def_builtin (mask, mask2, name, tcode, code);
if (decl)
TREE_READONLY (decl) = 1;
else
ix86_builtins_isa[(int) code].const_p = true;
return decl;
}
/* Like def_builtin, but also marks the function decl "pure". */
static inline tree
def_builtin_pure (HOST_WIDE_INT mask, HOST_WIDE_INT mask2, const char *name,
enum ix86_builtin_func_type tcode, enum ix86_builtins code)
{
tree decl = def_builtin (mask, mask2, name, tcode, code);
if (decl)
DECL_PURE_P (decl) = 1;
else
ix86_builtins_isa[(int) code].pure_p = true;
return decl;
}
/* Add any new builtin functions for a given ISA that may not have been
declared. This saves a bit of space compared to adding all of the
declarations to the tree, even if we didn't use them. */
void
ix86_add_new_builtins (HOST_WIDE_INT isa, HOST_WIDE_INT isa2)
{
isa &= ~OPTION_MASK_ISA_64BIT;
if ((isa & deferred_isa_values) == 0
&& (isa2 & deferred_isa_values2) == 0
&& ((deferred_isa_values & OPTION_MASK_ISA_MMX) == 0
|| !(TARGET_64BIT && (isa & OPTION_MASK_ISA_SSE2) != 0)))
return;
/* Bits in ISA value can be removed from potential isa values. */
deferred_isa_values &= ~isa;
deferred_isa_values2 &= ~isa2;
if (TARGET_64BIT && (isa & OPTION_MASK_ISA_SSE2) != 0)
deferred_isa_values &= ~OPTION_MASK_ISA_MMX;
int i;
tree saved_current_target_pragma = current_target_pragma;
current_target_pragma = NULL_TREE;
for (i = 0; i < (int)IX86_BUILTIN_MAX; i++)
{
if (((ix86_builtins_isa[i].isa & isa) != 0
|| (ix86_builtins_isa[i].isa2 & isa2) != 0
|| ((ix86_builtins_isa[i].isa & OPTION_MASK_ISA_MMX) != 0
&& TARGET_64BIT
&& (isa & OPTION_MASK_ISA_SSE2) != 0))
&& ix86_builtins_isa[i].set_and_not_built_p)
{
tree decl, type;
/* Don't define the builtin again. */
ix86_builtins_isa[i].set_and_not_built_p = false;
type = ix86_get_builtin_func_type (ix86_builtins_isa[i].tcode);
decl = add_builtin_function_ext_scope (ix86_builtins_isa[i].name,
type, i, BUILT_IN_MD, NULL,
NULL_TREE);
ix86_builtins[i] = decl;
if (ix86_builtins_isa[i].const_p)
TREE_READONLY (decl) = 1;
}
}
current_target_pragma = saved_current_target_pragma;
}
/* TM vector builtins. */
/* Reuse the existing x86-specific `struct builtin_description' cause
we're lazy. Add casts to make them fit. */
static const struct builtin_description bdesc_tm[] =
{
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_WM64", (enum ix86_builtins) BUILT_IN_TM_STORE_M64, UNKNOWN, VOID_FTYPE_PV2SI_V2SI },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_WaRM64", (enum ix86_builtins) BUILT_IN_TM_STORE_WAR_M64, UNKNOWN, VOID_FTYPE_PV2SI_V2SI },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_WaWM64", (enum ix86_builtins) BUILT_IN_TM_STORE_WAW_M64, UNKNOWN, VOID_FTYPE_PV2SI_V2SI },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_RM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_RaRM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAR_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_RaWM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAW_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_RfWM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_RFW_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_WM128", (enum ix86_builtins) BUILT_IN_TM_STORE_M128, UNKNOWN, VOID_FTYPE_PV4SF_V4SF },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_WaRM128", (enum ix86_builtins) BUILT_IN_TM_STORE_WAR_M128, UNKNOWN, VOID_FTYPE_PV4SF_V4SF },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_WaWM128", (enum ix86_builtins) BUILT_IN_TM_STORE_WAW_M128, UNKNOWN, VOID_FTYPE_PV4SF_V4SF },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_RM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_RaRM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAR_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_RaWM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAW_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_RfWM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_RFW_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_WM256", (enum ix86_builtins) BUILT_IN_TM_STORE_M256, UNKNOWN, VOID_FTYPE_PV8SF_V8SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_WaRM256", (enum ix86_builtins) BUILT_IN_TM_STORE_WAR_M256, UNKNOWN, VOID_FTYPE_PV8SF_V8SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_WaWM256", (enum ix86_builtins) BUILT_IN_TM_STORE_WAW_M256, UNKNOWN, VOID_FTYPE_PV8SF_V8SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_RM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_RaRM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAR_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_RaWM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAW_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_RfWM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_RFW_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_MMX, 0, CODE_FOR_nothing, "__builtin__ITM_LM64", (enum ix86_builtins) BUILT_IN_TM_LOG_M64, UNKNOWN, VOID_FTYPE_PCVOID },
{ OPTION_MASK_ISA_SSE, 0, CODE_FOR_nothing, "__builtin__ITM_LM128", (enum ix86_builtins) BUILT_IN_TM_LOG_M128, UNKNOWN, VOID_FTYPE_PCVOID },
{ OPTION_MASK_ISA_AVX, 0, CODE_FOR_nothing, "__builtin__ITM_LM256", (enum ix86_builtins) BUILT_IN_TM_LOG_M256, UNKNOWN, VOID_FTYPE_PCVOID },
};
/* Initialize the transactional memory vector load/store builtins. */
static void
ix86_init_tm_builtins (void)
{
enum ix86_builtin_func_type ftype;
const struct builtin_description *d;
size_t i;
tree decl;
tree attrs_load, attrs_type_load, attrs_store, attrs_type_store;
tree attrs_log, attrs_type_log;
if (!flag_tm)
return;
/* If there are no builtins defined, we must be compiling in a
language without trans-mem support. */
if (!builtin_decl_explicit_p (BUILT_IN_TM_LOAD_1))
return;
/* Use whatever attributes a normal TM load has. */
decl = builtin_decl_explicit (BUILT_IN_TM_LOAD_1);
attrs_load = DECL_ATTRIBUTES (decl);
attrs_type_load = TYPE_ATTRIBUTES (TREE_TYPE (decl));
/* Use whatever attributes a normal TM store has. */
decl = builtin_decl_explicit (BUILT_IN_TM_STORE_1);
attrs_store = DECL_ATTRIBUTES (decl);
attrs_type_store = TYPE_ATTRIBUTES (TREE_TYPE (decl));
/* Use whatever attributes a normal TM log has. */
decl = builtin_decl_explicit (BUILT_IN_TM_LOG);
attrs_log = DECL_ATTRIBUTES (decl);
attrs_type_log = TYPE_ATTRIBUTES (TREE_TYPE (decl));
for (i = 0, d = bdesc_tm;
i < ARRAY_SIZE (bdesc_tm);
i++, d++)
{
if ((d->mask & ix86_isa_flags) != 0
|| ((d->mask & OPTION_MASK_ISA_MMX) != 0 && TARGET_MMX_WITH_SSE)
|| (lang_hooks.builtin_function
== lang_hooks.builtin_function_ext_scope))
{
tree type, attrs, attrs_type;
enum built_in_function code = (enum built_in_function) d->code;
ftype = (enum ix86_builtin_func_type) d->flag;
type = ix86_get_builtin_func_type (ftype);
if (BUILTIN_TM_LOAD_P (code))
{
attrs = attrs_load;
attrs_type = attrs_type_load;
}
else if (BUILTIN_TM_STORE_P (code))
{
attrs = attrs_store;
attrs_type = attrs_type_store;
}
else
{
attrs = attrs_log;
attrs_type = attrs_type_log;
}
decl = add_builtin_function (d->name, type, code, BUILT_IN_NORMAL,
/* The builtin without the prefix for
calling it directly. */
d->name + strlen ("__builtin_"),
attrs);
/* add_builtin_function() will set the DECL_ATTRIBUTES, now
set the TYPE_ATTRIBUTES. */
decl_attributes (&TREE_TYPE (decl), attrs_type, ATTR_FLAG_BUILT_IN);
set_builtin_decl (code, decl, false);
}
}
}
/* Set up all the MMX/SSE builtins, even builtins for instructions that are not
in the current target ISA to allow the user to compile particular modules
with different target specific options that differ from the command line
options. */
static void
ix86_init_mmx_sse_builtins (void)
{
const struct builtin_description * d;
enum ix86_builtin_func_type ftype;
size_t i;
/* Add all special builtins with variable number of operands. */
for (i = 0, d = bdesc_special_args;
i < ARRAY_SIZE (bdesc_special_args);
i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_SPECIAL_ARGS_FIRST, i);
if (d->name == 0)
continue;
ftype = (enum ix86_builtin_func_type) d->flag;
def_builtin (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_SPECIAL_ARGS_LAST,
IX86_BUILTIN__BDESC_SPECIAL_ARGS_FIRST,
ARRAY_SIZE (bdesc_special_args) - 1);
/* Add all pure builtins with variable number of operands. */
for (i = 0, d = bdesc_pure_args;
i < ARRAY_SIZE (bdesc_pure_args);
i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_PURE_ARGS_FIRST, i);
if (d->name == 0)
continue;
ftype = (enum ix86_builtin_func_type) d->flag;
def_builtin_pure (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_PURE_ARGS_LAST,
IX86_BUILTIN__BDESC_PURE_ARGS_FIRST,
ARRAY_SIZE (bdesc_pure_args) - 1);
/* Add all const builtins with variable number of operands. */
for (i = 0, d = bdesc_args;
i < ARRAY_SIZE (bdesc_args);
i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_ARGS_FIRST, i);
if (d->name == 0)
continue;
ftype = (enum ix86_builtin_func_type) d->flag;
def_builtin_const (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_ARGS_LAST,
IX86_BUILTIN__BDESC_ARGS_FIRST,
ARRAY_SIZE (bdesc_args) - 1);
/* Add all builtins with rounding. */
for (i = 0, d = bdesc_round_args;
i < ARRAY_SIZE (bdesc_round_args);
i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_ROUND_ARGS_FIRST, i);
if (d->name == 0)
continue;
ftype = (enum ix86_builtin_func_type) d->flag;
def_builtin_const (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_ROUND_ARGS_LAST,
IX86_BUILTIN__BDESC_ROUND_ARGS_FIRST,
ARRAY_SIZE (bdesc_round_args) - 1);
/* pcmpestr[im] insns. */
for (i = 0, d = bdesc_pcmpestr;
i < ARRAY_SIZE (bdesc_pcmpestr);
i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_PCMPESTR_FIRST, i);
if (d->code == IX86_BUILTIN_PCMPESTRM128)
ftype = V16QI_FTYPE_V16QI_INT_V16QI_INT_INT;
else
ftype = INT_FTYPE_V16QI_INT_V16QI_INT_INT;
def_builtin_const (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_PCMPESTR_LAST,
IX86_BUILTIN__BDESC_PCMPESTR_FIRST,
ARRAY_SIZE (bdesc_pcmpestr) - 1);
/* pcmpistr[im] insns. */
for (i = 0, d = bdesc_pcmpistr;
i < ARRAY_SIZE (bdesc_pcmpistr);
i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_PCMPISTR_FIRST, i);
if (d->code == IX86_BUILTIN_PCMPISTRM128)
ftype = V16QI_FTYPE_V16QI_V16QI_INT;
else
ftype = INT_FTYPE_V16QI_V16QI_INT;
def_builtin_const (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_PCMPISTR_LAST,
IX86_BUILTIN__BDESC_PCMPISTR_FIRST,
ARRAY_SIZE (bdesc_pcmpistr) - 1);
/* comi/ucomi insns. */
for (i = 0, d = bdesc_comi; i < ARRAY_SIZE (bdesc_comi); i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_COMI_FIRST, i);
if (d->mask == OPTION_MASK_ISA_SSE2)
ftype = INT_FTYPE_V2DF_V2DF;
else
ftype = INT_FTYPE_V4SF_V4SF;
def_builtin_const (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_COMI_LAST,
IX86_BUILTIN__BDESC_COMI_FIRST,
ARRAY_SIZE (bdesc_comi) - 1);
/* SSE */
def_builtin (OPTION_MASK_ISA_SSE, 0, "__builtin_ia32_ldmxcsr",
VOID_FTYPE_UNSIGNED, IX86_BUILTIN_LDMXCSR);
def_builtin_pure (OPTION_MASK_ISA_SSE, 0, "__builtin_ia32_stmxcsr",
UNSIGNED_FTYPE_VOID, IX86_BUILTIN_STMXCSR);
/* SSE or 3DNow!A */
def_builtin (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A
/* As it uses V4HImode, we have to require -mmmx too. */
| OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_maskmovq", VOID_FTYPE_V8QI_V8QI_PCHAR,
IX86_BUILTIN_MASKMOVQ);
/* SSE2 */
def_builtin (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_maskmovdqu",
VOID_FTYPE_V16QI_V16QI_PCHAR, IX86_BUILTIN_MASKMOVDQU);
def_builtin (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_clflush",
VOID_FTYPE_PCVOID, IX86_BUILTIN_CLFLUSH);
x86_mfence = def_builtin (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_mfence",
VOID_FTYPE_VOID, IX86_BUILTIN_MFENCE);
/* SSE3. */
def_builtin (0, OPTION_MASK_ISA2_MWAIT, "__builtin_ia32_monitor",
VOID_FTYPE_PCVOID_UNSIGNED_UNSIGNED, IX86_BUILTIN_MONITOR);
def_builtin (0, OPTION_MASK_ISA2_MWAIT, "__builtin_ia32_mwait",
VOID_FTYPE_UNSIGNED_UNSIGNED, IX86_BUILTIN_MWAIT);
/* AES */
def_builtin_const (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_aesenc128",
V2DI_FTYPE_V2DI_V2DI, IX86_BUILTIN_AESENC128);
def_builtin_const (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_aesenclast128",
V2DI_FTYPE_V2DI_V2DI, IX86_BUILTIN_AESENCLAST128);
def_builtin_const (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_aesdec128",
V2DI_FTYPE_V2DI_V2DI, IX86_BUILTIN_AESDEC128);
def_builtin_const (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_aesdeclast128",
V2DI_FTYPE_V2DI_V2DI, IX86_BUILTIN_AESDECLAST128);
def_builtin_const (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_aesimc128",
V2DI_FTYPE_V2DI, IX86_BUILTIN_AESIMC128);
def_builtin_const (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_aeskeygenassist128",
V2DI_FTYPE_V2DI_INT, IX86_BUILTIN_AESKEYGENASSIST128);
/* PCLMUL */
def_builtin_const (OPTION_MASK_ISA_PCLMUL | OPTION_MASK_ISA_SSE2, 0,
"__builtin_ia32_pclmulqdq128",
V2DI_FTYPE_V2DI_V2DI_INT, IX86_BUILTIN_PCLMULQDQ128);
/* RDRND */
def_builtin (OPTION_MASK_ISA_RDRND, 0, "__builtin_ia32_rdrand16_step",
INT_FTYPE_PUSHORT, IX86_BUILTIN_RDRAND16_STEP);
def_builtin (OPTION_MASK_ISA_RDRND, 0, "__builtin_ia32_rdrand32_step",
INT_FTYPE_PUNSIGNED, IX86_BUILTIN_RDRAND32_STEP);
def_builtin (OPTION_MASK_ISA_RDRND | OPTION_MASK_ISA_64BIT, 0,
"__builtin_ia32_rdrand64_step", INT_FTYPE_PULONGLONG,
IX86_BUILTIN_RDRAND64_STEP);
/* AVX2 */
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv2df",
V2DF_FTYPE_V2DF_PCDOUBLE_V4SI_V2DF_INT,
IX86_BUILTIN_GATHERSIV2DF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv4df",
V4DF_FTYPE_V4DF_PCDOUBLE_V4SI_V4DF_INT,
IX86_BUILTIN_GATHERSIV4DF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv2df",
V2DF_FTYPE_V2DF_PCDOUBLE_V2DI_V2DF_INT,
IX86_BUILTIN_GATHERDIV2DF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv4df",
V4DF_FTYPE_V4DF_PCDOUBLE_V4DI_V4DF_INT,
IX86_BUILTIN_GATHERDIV4DF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv4sf",
V4SF_FTYPE_V4SF_PCFLOAT_V4SI_V4SF_INT,
IX86_BUILTIN_GATHERSIV4SF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv8sf",
V8SF_FTYPE_V8SF_PCFLOAT_V8SI_V8SF_INT,
IX86_BUILTIN_GATHERSIV8SF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv4sf",
V4SF_FTYPE_V4SF_PCFLOAT_V2DI_V4SF_INT,
IX86_BUILTIN_GATHERDIV4SF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv4sf256",
V4SF_FTYPE_V4SF_PCFLOAT_V4DI_V4SF_INT,
IX86_BUILTIN_GATHERDIV8SF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv2di",
V2DI_FTYPE_V2DI_PCINT64_V4SI_V2DI_INT,
IX86_BUILTIN_GATHERSIV2DI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv4di",
V4DI_FTYPE_V4DI_PCINT64_V4SI_V4DI_INT,
IX86_BUILTIN_GATHERSIV4DI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv2di",
V2DI_FTYPE_V2DI_PCINT64_V2DI_V2DI_INT,
IX86_BUILTIN_GATHERDIV2DI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv4di",
V4DI_FTYPE_V4DI_PCINT64_V4DI_V4DI_INT,
IX86_BUILTIN_GATHERDIV4DI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv4si",
V4SI_FTYPE_V4SI_PCINT_V4SI_V4SI_INT,
IX86_BUILTIN_GATHERSIV4SI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gathersiv8si",
V8SI_FTYPE_V8SI_PCINT_V8SI_V8SI_INT,
IX86_BUILTIN_GATHERSIV8SI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv4si",
V4SI_FTYPE_V4SI_PCINT_V2DI_V4SI_INT,
IX86_BUILTIN_GATHERDIV4SI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatherdiv4si256",
V4SI_FTYPE_V4SI_PCINT_V4DI_V4SI_INT,
IX86_BUILTIN_GATHERDIV8SI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatheraltsiv4df ",
V4DF_FTYPE_V4DF_PCDOUBLE_V8SI_V4DF_INT,
IX86_BUILTIN_GATHERALTSIV4DF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatheraltdiv8sf ",
V8SF_FTYPE_V8SF_PCFLOAT_V4DI_V8SF_INT,
IX86_BUILTIN_GATHERALTDIV8SF);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatheraltsiv4di ",
V4DI_FTYPE_V4DI_PCINT64_V8SI_V4DI_INT,
IX86_BUILTIN_GATHERALTSIV4DI);
def_builtin_pure (OPTION_MASK_ISA_AVX2, 0, "__builtin_ia32_gatheraltdiv8si ",
V8SI_FTYPE_V8SI_PCINT_V4DI_V8SI_INT,
IX86_BUILTIN_GATHERALTDIV8SI);
/* AVX512F */
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gathersiv16sf",
V16SF_FTYPE_V16SF_PCVOID_V16SI_HI_INT,
IX86_BUILTIN_GATHER3SIV16SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gathersiv8df",
V8DF_FTYPE_V8DF_PCVOID_V8SI_QI_INT,
IX86_BUILTIN_GATHER3SIV8DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gatherdiv16sf",
V8SF_FTYPE_V8SF_PCVOID_V8DI_QI_INT,
IX86_BUILTIN_GATHER3DIV16SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gatherdiv8df",
V8DF_FTYPE_V8DF_PCVOID_V8DI_QI_INT,
IX86_BUILTIN_GATHER3DIV8DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gathersiv16si",
V16SI_FTYPE_V16SI_PCVOID_V16SI_HI_INT,
IX86_BUILTIN_GATHER3SIV16SI);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gathersiv8di",
V8DI_FTYPE_V8DI_PCVOID_V8SI_QI_INT,
IX86_BUILTIN_GATHER3SIV8DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gatherdiv16si",
V8SI_FTYPE_V8SI_PCVOID_V8DI_QI_INT,
IX86_BUILTIN_GATHER3DIV16SI);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gatherdiv8di",
V8DI_FTYPE_V8DI_PCVOID_V8DI_QI_INT,
IX86_BUILTIN_GATHER3DIV8DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gather3altsiv8df ",
V8DF_FTYPE_V8DF_PCDOUBLE_V16SI_QI_INT,
IX86_BUILTIN_GATHER3ALTSIV8DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gather3altdiv16sf ",
V16SF_FTYPE_V16SF_PCFLOAT_V8DI_HI_INT,
IX86_BUILTIN_GATHER3ALTDIV16SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gather3altsiv8di ",
V8DI_FTYPE_V8DI_PCINT64_V16SI_QI_INT,
IX86_BUILTIN_GATHER3ALTSIV8DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_gather3altdiv16si ",
V16SI_FTYPE_V16SI_PCINT_V8DI_HI_INT,
IX86_BUILTIN_GATHER3ALTDIV16SI);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scattersiv16sf",
VOID_FTYPE_PVOID_HI_V16SI_V16SF_INT,
IX86_BUILTIN_SCATTERSIV16SF);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scattersiv8df",
VOID_FTYPE_PVOID_QI_V8SI_V8DF_INT,
IX86_BUILTIN_SCATTERSIV8DF);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatterdiv16sf",
VOID_FTYPE_PVOID_QI_V8DI_V8SF_INT,
IX86_BUILTIN_SCATTERDIV16SF);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatterdiv8df",
VOID_FTYPE_PVOID_QI_V8DI_V8DF_INT,
IX86_BUILTIN_SCATTERDIV8DF);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scattersiv16si",
VOID_FTYPE_PVOID_HI_V16SI_V16SI_INT,
IX86_BUILTIN_SCATTERSIV16SI);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scattersiv8di",
VOID_FTYPE_PVOID_QI_V8SI_V8DI_INT,
IX86_BUILTIN_SCATTERSIV8DI);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatterdiv16si",
VOID_FTYPE_PVOID_QI_V8DI_V8SI_INT,
IX86_BUILTIN_SCATTERDIV16SI);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatterdiv8di",
VOID_FTYPE_PVOID_QI_V8DI_V8DI_INT,
IX86_BUILTIN_SCATTERDIV8DI);
/* AVX512VL */
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv2df",
V2DF_FTYPE_V2DF_PCVOID_V4SI_QI_INT,
IX86_BUILTIN_GATHER3SIV2DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv4df",
V4DF_FTYPE_V4DF_PCVOID_V4SI_QI_INT,
IX86_BUILTIN_GATHER3SIV4DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div2df",
V2DF_FTYPE_V2DF_PCVOID_V2DI_QI_INT,
IX86_BUILTIN_GATHER3DIV2DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div4df",
V4DF_FTYPE_V4DF_PCVOID_V4DI_QI_INT,
IX86_BUILTIN_GATHER3DIV4DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv4sf",
V4SF_FTYPE_V4SF_PCVOID_V4SI_QI_INT,
IX86_BUILTIN_GATHER3SIV4SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv8sf",
V8SF_FTYPE_V8SF_PCVOID_V8SI_QI_INT,
IX86_BUILTIN_GATHER3SIV8SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div4sf",
V4SF_FTYPE_V4SF_PCVOID_V2DI_QI_INT,
IX86_BUILTIN_GATHER3DIV4SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div8sf",
V4SF_FTYPE_V4SF_PCVOID_V4DI_QI_INT,
IX86_BUILTIN_GATHER3DIV8SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv2di",
V2DI_FTYPE_V2DI_PCVOID_V4SI_QI_INT,
IX86_BUILTIN_GATHER3SIV2DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv4di",
V4DI_FTYPE_V4DI_PCVOID_V4SI_QI_INT,
IX86_BUILTIN_GATHER3SIV4DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div2di",
V2DI_FTYPE_V2DI_PCVOID_V2DI_QI_INT,
IX86_BUILTIN_GATHER3DIV2DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div4di",
V4DI_FTYPE_V4DI_PCVOID_V4DI_QI_INT,
IX86_BUILTIN_GATHER3DIV4DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv4si",
V4SI_FTYPE_V4SI_PCVOID_V4SI_QI_INT,
IX86_BUILTIN_GATHER3SIV4SI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3siv8si",
V8SI_FTYPE_V8SI_PCVOID_V8SI_QI_INT,
IX86_BUILTIN_GATHER3SIV8SI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div4si",
V4SI_FTYPE_V4SI_PCVOID_V2DI_QI_INT,
IX86_BUILTIN_GATHER3DIV4SI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3div8si",
V4SI_FTYPE_V4SI_PCVOID_V4DI_QI_INT,
IX86_BUILTIN_GATHER3DIV8SI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3altsiv4df ",
V4DF_FTYPE_V4DF_PCDOUBLE_V8SI_QI_INT,
IX86_BUILTIN_GATHER3ALTSIV4DF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3altdiv8sf ",
V8SF_FTYPE_V8SF_PCFLOAT_V4DI_QI_INT,
IX86_BUILTIN_GATHER3ALTDIV8SF);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3altsiv4di ",
V4DI_FTYPE_V4DI_PCINT64_V8SI_QI_INT,
IX86_BUILTIN_GATHER3ALTSIV4DI);
def_builtin_pure (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_gather3altdiv8si ",
V8SI_FTYPE_V8SI_PCINT_V4DI_QI_INT,
IX86_BUILTIN_GATHER3ALTDIV8SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv8sf",
VOID_FTYPE_PVOID_QI_V8SI_V8SF_INT,
IX86_BUILTIN_SCATTERSIV8SF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv4sf",
VOID_FTYPE_PVOID_QI_V4SI_V4SF_INT,
IX86_BUILTIN_SCATTERSIV4SF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv4df",
VOID_FTYPE_PVOID_QI_V4SI_V4DF_INT,
IX86_BUILTIN_SCATTERSIV4DF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv2df",
VOID_FTYPE_PVOID_QI_V4SI_V2DF_INT,
IX86_BUILTIN_SCATTERSIV2DF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv8sf",
VOID_FTYPE_PVOID_QI_V4DI_V4SF_INT,
IX86_BUILTIN_SCATTERDIV8SF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv4sf",
VOID_FTYPE_PVOID_QI_V2DI_V4SF_INT,
IX86_BUILTIN_SCATTERDIV4SF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv4df",
VOID_FTYPE_PVOID_QI_V4DI_V4DF_INT,
IX86_BUILTIN_SCATTERDIV4DF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv2df",
VOID_FTYPE_PVOID_QI_V2DI_V2DF_INT,
IX86_BUILTIN_SCATTERDIV2DF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv8si",
VOID_FTYPE_PVOID_QI_V8SI_V8SI_INT,
IX86_BUILTIN_SCATTERSIV8SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv4si",
VOID_FTYPE_PVOID_QI_V4SI_V4SI_INT,
IX86_BUILTIN_SCATTERSIV4SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv4di",
VOID_FTYPE_PVOID_QI_V4SI_V4DI_INT,
IX86_BUILTIN_SCATTERSIV4DI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scattersiv2di",
VOID_FTYPE_PVOID_QI_V4SI_V2DI_INT,
IX86_BUILTIN_SCATTERSIV2DI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv8si",
VOID_FTYPE_PVOID_QI_V4DI_V4SI_INT,
IX86_BUILTIN_SCATTERDIV8SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv4si",
VOID_FTYPE_PVOID_QI_V2DI_V4SI_INT,
IX86_BUILTIN_SCATTERDIV4SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv4di",
VOID_FTYPE_PVOID_QI_V4DI_V4DI_INT,
IX86_BUILTIN_SCATTERDIV4DI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatterdiv2di",
VOID_FTYPE_PVOID_QI_V2DI_V2DI_INT,
IX86_BUILTIN_SCATTERDIV2DI);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatteraltsiv8df ",
VOID_FTYPE_PDOUBLE_QI_V16SI_V8DF_INT,
IX86_BUILTIN_SCATTERALTSIV8DF);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatteraltdiv16sf ",
VOID_FTYPE_PFLOAT_HI_V8DI_V16SF_INT,
IX86_BUILTIN_SCATTERALTDIV16SF);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatteraltsiv8di ",
VOID_FTYPE_PLONGLONG_QI_V16SI_V8DI_INT,
IX86_BUILTIN_SCATTERALTSIV8DI);
def_builtin (OPTION_MASK_ISA_AVX512F, 0, "__builtin_ia32_scatteraltdiv16si ",
VOID_FTYPE_PINT_HI_V8DI_V16SI_INT,
IX86_BUILTIN_SCATTERALTDIV16SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltsiv4df ",
VOID_FTYPE_PDOUBLE_QI_V8SI_V4DF_INT,
IX86_BUILTIN_SCATTERALTSIV4DF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltdiv8sf ",
VOID_FTYPE_PFLOAT_QI_V4DI_V8SF_INT,
IX86_BUILTIN_SCATTERALTDIV8SF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltsiv4di ",
VOID_FTYPE_PLONGLONG_QI_V8SI_V4DI_INT,
IX86_BUILTIN_SCATTERALTSIV4DI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltdiv8si ",
VOID_FTYPE_PINT_QI_V4DI_V8SI_INT,
IX86_BUILTIN_SCATTERALTDIV8SI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltsiv2df ",
VOID_FTYPE_PDOUBLE_QI_V4SI_V2DF_INT,
IX86_BUILTIN_SCATTERALTSIV2DF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltdiv4sf ",
VOID_FTYPE_PFLOAT_QI_V2DI_V4SF_INT,
IX86_BUILTIN_SCATTERALTDIV4SF);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltsiv2di ",
VOID_FTYPE_PLONGLONG_QI_V4SI_V2DI_INT,
IX86_BUILTIN_SCATTERALTSIV2DI);
def_builtin (OPTION_MASK_ISA_AVX512VL, 0, "__builtin_ia32_scatteraltdiv4si ",
VOID_FTYPE_PINT_QI_V2DI_V4SI_INT,
IX86_BUILTIN_SCATTERALTDIV4SI);
/* AVX512PF */
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_gatherpfdpd",
VOID_FTYPE_QI_V8SI_PCVOID_INT_INT,
IX86_BUILTIN_GATHERPFDPD);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_gatherpfdps",
VOID_FTYPE_HI_V16SI_PCVOID_INT_INT,
IX86_BUILTIN_GATHERPFDPS);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_gatherpfqpd",
VOID_FTYPE_QI_V8DI_PCVOID_INT_INT,
IX86_BUILTIN_GATHERPFQPD);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_gatherpfqps",
VOID_FTYPE_QI_V8DI_PCVOID_INT_INT,
IX86_BUILTIN_GATHERPFQPS);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_scatterpfdpd",
VOID_FTYPE_QI_V8SI_PCVOID_INT_INT,
IX86_BUILTIN_SCATTERPFDPD);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_scatterpfdps",
VOID_FTYPE_HI_V16SI_PCVOID_INT_INT,
IX86_BUILTIN_SCATTERPFDPS);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_scatterpfqpd",
VOID_FTYPE_QI_V8DI_PCVOID_INT_INT,
IX86_BUILTIN_SCATTERPFQPD);
def_builtin (OPTION_MASK_ISA_AVX512PF, 0, "__builtin_ia32_scatterpfqps",
VOID_FTYPE_QI_V8DI_PCVOID_INT_INT,
IX86_BUILTIN_SCATTERPFQPS);
/* SHA */
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha1msg1",
V4SI_FTYPE_V4SI_V4SI, IX86_BUILTIN_SHA1MSG1);
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha1msg2",
V4SI_FTYPE_V4SI_V4SI, IX86_BUILTIN_SHA1MSG2);
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha1nexte",
V4SI_FTYPE_V4SI_V4SI, IX86_BUILTIN_SHA1NEXTE);
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha1rnds4",
V4SI_FTYPE_V4SI_V4SI_INT, IX86_BUILTIN_SHA1RNDS4);
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha256msg1",
V4SI_FTYPE_V4SI_V4SI, IX86_BUILTIN_SHA256MSG1);
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha256msg2",
V4SI_FTYPE_V4SI_V4SI, IX86_BUILTIN_SHA256MSG2);
def_builtin_const (OPTION_MASK_ISA_SHA, 0, "__builtin_ia32_sha256rnds2",
V4SI_FTYPE_V4SI_V4SI_V4SI, IX86_BUILTIN_SHA256RNDS2);
/* RTM. */
def_builtin (OPTION_MASK_ISA_RTM, 0, "__builtin_ia32_xabort",
VOID_FTYPE_UNSIGNED, IX86_BUILTIN_XABORT);
/* MMX access to the vec_init patterns. */
def_builtin_const (OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_vec_init_v2si",
V2SI_FTYPE_INT_INT, IX86_BUILTIN_VEC_INIT_V2SI);
def_builtin_const (OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_vec_init_v4hi",
V4HI_FTYPE_HI_HI_HI_HI,
IX86_BUILTIN_VEC_INIT_V4HI);
def_builtin_const (OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_vec_init_v8qi",
V8QI_FTYPE_QI_QI_QI_QI_QI_QI_QI_QI,
IX86_BUILTIN_VEC_INIT_V8QI);
/* Access to the vec_extract patterns. */
def_builtin_const (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_vec_ext_v2df",
DOUBLE_FTYPE_V2DF_INT, IX86_BUILTIN_VEC_EXT_V2DF);
def_builtin_const (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_vec_ext_v2di",
DI_FTYPE_V2DI_INT, IX86_BUILTIN_VEC_EXT_V2DI);
def_builtin_const (OPTION_MASK_ISA_SSE, 0, "__builtin_ia32_vec_ext_v4sf",
FLOAT_FTYPE_V4SF_INT, IX86_BUILTIN_VEC_EXT_V4SF);
def_builtin_const (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_vec_ext_v4si",
SI_FTYPE_V4SI_INT, IX86_BUILTIN_VEC_EXT_V4SI);
def_builtin_const (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_vec_ext_v8hi",
HI_FTYPE_V8HI_INT, IX86_BUILTIN_VEC_EXT_V8HI);
def_builtin_const (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A
/* As it uses V4HImode, we have to require -mmmx too. */
| OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_vec_ext_v4hi",
HI_FTYPE_V4HI_INT, IX86_BUILTIN_VEC_EXT_V4HI);
def_builtin_const (OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_vec_ext_v2si",
SI_FTYPE_V2SI_INT, IX86_BUILTIN_VEC_EXT_V2SI);
def_builtin_const (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_vec_ext_v16qi",
QI_FTYPE_V16QI_INT, IX86_BUILTIN_VEC_EXT_V16QI);
/* Access to the vec_set patterns. */
def_builtin_const (OPTION_MASK_ISA_SSE4_1 | OPTION_MASK_ISA_64BIT, 0,
"__builtin_ia32_vec_set_v2di",
V2DI_FTYPE_V2DI_DI_INT, IX86_BUILTIN_VEC_SET_V2DI);
def_builtin_const (OPTION_MASK_ISA_SSE4_1, 0, "__builtin_ia32_vec_set_v4sf",
V4SF_FTYPE_V4SF_FLOAT_INT, IX86_BUILTIN_VEC_SET_V4SF);
def_builtin_const (OPTION_MASK_ISA_SSE4_1, 0, "__builtin_ia32_vec_set_v4si",
V4SI_FTYPE_V4SI_SI_INT, IX86_BUILTIN_VEC_SET_V4SI);
def_builtin_const (OPTION_MASK_ISA_SSE2, 0, "__builtin_ia32_vec_set_v8hi",
V8HI_FTYPE_V8HI_HI_INT, IX86_BUILTIN_VEC_SET_V8HI);
def_builtin_const (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A
/* As it uses V4HImode, we have to require -mmmx too. */
| OPTION_MASK_ISA_MMX, 0,
"__builtin_ia32_vec_set_v4hi",
V4HI_FTYPE_V4HI_HI_INT, IX86_BUILTIN_VEC_SET_V4HI);
def_builtin_const (OPTION_MASK_ISA_SSE4_1, 0, "__builtin_ia32_vec_set_v16qi",
V16QI_FTYPE_V16QI_QI_INT, IX86_BUILTIN_VEC_SET_V16QI);
/* RDSEED */
def_builtin (OPTION_MASK_ISA_RDSEED, 0, "__builtin_ia32_rdseed_hi_step",
INT_FTYPE_PUSHORT, IX86_BUILTIN_RDSEED16_STEP);
def_builtin (OPTION_MASK_ISA_RDSEED, 0, "__builtin_ia32_rdseed_si_step",
INT_FTYPE_PUNSIGNED, IX86_BUILTIN_RDSEED32_STEP);
def_builtin (OPTION_MASK_ISA_RDSEED | OPTION_MASK_ISA_64BIT, 0,
"__builtin_ia32_rdseed_di_step",
INT_FTYPE_PULONGLONG, IX86_BUILTIN_RDSEED64_STEP);
/* ADCX */
def_builtin (0, 0, "__builtin_ia32_addcarryx_u32",
UCHAR_FTYPE_UCHAR_UINT_UINT_PUNSIGNED, IX86_BUILTIN_ADDCARRYX32);
def_builtin (OPTION_MASK_ISA_64BIT, 0,
"__builtin_ia32_addcarryx_u64",
UCHAR_FTYPE_UCHAR_ULONGLONG_ULONGLONG_PULONGLONG,
IX86_BUILTIN_ADDCARRYX64);
/* SBB */
def_builtin (0, 0, "__builtin_ia32_sbb_u32",
UCHAR_FTYPE_UCHAR_UINT_UINT_PUNSIGNED, IX86_BUILTIN_SBB32);
def_builtin (OPTION_MASK_ISA_64BIT, 0,
"__builtin_ia32_sbb_u64",
UCHAR_FTYPE_UCHAR_ULONGLONG_ULONGLONG_PULONGLONG,
IX86_BUILTIN_SBB64);
/* Read/write FLAGS. */
if (TARGET_64BIT)
{
def_builtin (OPTION_MASK_ISA_64BIT, 0, "__builtin_ia32_readeflags_u64",
UINT64_FTYPE_VOID, IX86_BUILTIN_READ_FLAGS);
def_builtin (OPTION_MASK_ISA_64BIT, 0, "__builtin_ia32_writeeflags_u64",
VOID_FTYPE_UINT64, IX86_BUILTIN_WRITE_FLAGS);
}
else
{
def_builtin (0, 0, "__builtin_ia32_readeflags_u32",
UNSIGNED_FTYPE_VOID, IX86_BUILTIN_READ_FLAGS);
def_builtin (0, 0, "__builtin_ia32_writeeflags_u32",
VOID_FTYPE_UNSIGNED, IX86_BUILTIN_WRITE_FLAGS);
}
/* CLFLUSHOPT. */
def_builtin (OPTION_MASK_ISA_CLFLUSHOPT, 0, "__builtin_ia32_clflushopt",
VOID_FTYPE_PCVOID, IX86_BUILTIN_CLFLUSHOPT);
/* CLWB. */
def_builtin (OPTION_MASK_ISA_CLWB, 0, "__builtin_ia32_clwb",
VOID_FTYPE_PCVOID, IX86_BUILTIN_CLWB);
/* MONITORX and MWAITX. */
def_builtin (0, OPTION_MASK_ISA2_MWAITX, "__builtin_ia32_monitorx",
VOID_FTYPE_PCVOID_UNSIGNED_UNSIGNED, IX86_BUILTIN_MONITORX);
def_builtin (0, OPTION_MASK_ISA2_MWAITX, "__builtin_ia32_mwaitx",
VOID_FTYPE_UNSIGNED_UNSIGNED_UNSIGNED, IX86_BUILTIN_MWAITX);
/* CLZERO. */
def_builtin (0, OPTION_MASK_ISA2_CLZERO, "__builtin_ia32_clzero",
VOID_FTYPE_PCVOID, IX86_BUILTIN_CLZERO);
/* WAITPKG. */
def_builtin (0, OPTION_MASK_ISA2_WAITPKG, "__builtin_ia32_umonitor",
VOID_FTYPE_PVOID, IX86_BUILTIN_UMONITOR);
def_builtin (0, OPTION_MASK_ISA2_WAITPKG, "__builtin_ia32_umwait",
UINT8_FTYPE_UNSIGNED_UINT64, IX86_BUILTIN_UMWAIT);
def_builtin (0, OPTION_MASK_ISA2_WAITPKG, "__builtin_ia32_tpause",
UINT8_FTYPE_UNSIGNED_UINT64, IX86_BUILTIN_TPAUSE);
/* UINTR. */
def_builtin (OPTION_MASK_ISA_64BIT, OPTION_MASK_ISA2_UINTR,
"__builtin_ia32_testui",
UINT8_FTYPE_VOID, IX86_BUILTIN_TESTUI);
/* CLDEMOTE. */
def_builtin (0, OPTION_MASK_ISA2_CLDEMOTE, "__builtin_ia32_cldemote",
VOID_FTYPE_PCVOID, IX86_BUILTIN_CLDEMOTE);
/* Add FMA4 multi-arg argument instructions */
for (i = 0, d = bdesc_multi_arg; i < ARRAY_SIZE (bdesc_multi_arg); i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_MULTI_ARG_FIRST, i);
if (d->name == 0)
continue;
ftype = (enum ix86_builtin_func_type) d->flag;
def_builtin_const (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_MULTI_ARG_LAST,
IX86_BUILTIN__BDESC_MULTI_ARG_FIRST,
ARRAY_SIZE (bdesc_multi_arg) - 1);
/* Add CET inrinsics. */
for (i = 0, d = bdesc_cet; i < ARRAY_SIZE (bdesc_cet); i++, d++)
{
BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_CET_FIRST, i);
if (d->name == 0)
continue;
ftype = (enum ix86_builtin_func_type) d->flag;
def_builtin (d->mask, d->mask2, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_LAST,
IX86_BUILTIN__BDESC_CET_FIRST,
ARRAY_SIZE (bdesc_cet) - 1);
}
#undef BDESC_VERIFY
#undef BDESC_VERIFYS
/* Make builtins to detect cpu type and features supported. NAME is
the builtin name, CODE is the builtin code, and FTYPE is the function
type of the builtin. */
static void
make_cpu_type_builtin (const char* name, int code,
enum ix86_builtin_func_type ftype, bool is_const)
{
tree decl;
tree type;
type = ix86_get_builtin_func_type (ftype);
decl = add_builtin_function (name, type, code, BUILT_IN_MD,
NULL, NULL_TREE);
gcc_assert (decl != NULL_TREE);
ix86_builtins[(int) code] = decl;
TREE_READONLY (decl) = is_const;
}
/* Make builtins to get CPU type and features supported. The created
builtins are :
__builtin_cpu_init (), to detect cpu type and features,
__builtin_cpu_is (""), to check if cpu is of type ,
__builtin_cpu_supports (""), to check if cpu supports
*/
static void
ix86_init_platform_type_builtins (void)
{
make_cpu_type_builtin ("__builtin_cpu_init", IX86_BUILTIN_CPU_INIT,
INT_FTYPE_VOID, false);
make_cpu_type_builtin ("__builtin_cpu_is", IX86_BUILTIN_CPU_IS,
INT_FTYPE_PCCHAR, true);
make_cpu_type_builtin ("__builtin_cpu_supports", IX86_BUILTIN_CPU_SUPPORTS,
INT_FTYPE_PCCHAR, true);
}
/* Internal method for ix86_init_builtins. */
static void
ix86_init_builtins_va_builtins_abi (void)
{
tree ms_va_ref, sysv_va_ref;
tree fnvoid_va_end_ms, fnvoid_va_end_sysv;
tree fnvoid_va_start_ms, fnvoid_va_start_sysv;
tree fnvoid_va_copy_ms, fnvoid_va_copy_sysv;
tree fnattr_ms = NULL_TREE, fnattr_sysv = NULL_TREE;
if (!TARGET_64BIT)
return;
fnattr_ms = build_tree_list (get_identifier ("ms_abi"), NULL_TREE);
fnattr_sysv = build_tree_list (get_identifier ("sysv_abi"), NULL_TREE);
ms_va_ref = build_reference_type (ms_va_list_type_node);
sysv_va_ref = build_pointer_type (TREE_TYPE (sysv_va_list_type_node));
fnvoid_va_end_ms = build_function_type_list (void_type_node, ms_va_ref,
NULL_TREE);
fnvoid_va_start_ms
= build_varargs_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
fnvoid_va_end_sysv
= build_function_type_list (void_type_node, sysv_va_ref, NULL_TREE);
fnvoid_va_start_sysv
= build_varargs_function_type_list (void_type_node, sysv_va_ref,
NULL_TREE);
fnvoid_va_copy_ms
= build_function_type_list (void_type_node, ms_va_ref,
ms_va_list_type_node, NULL_TREE);
fnvoid_va_copy_sysv
= build_function_type_list (void_type_node, sysv_va_ref,
sysv_va_ref, NULL_TREE);
add_builtin_function ("__builtin_ms_va_start", fnvoid_va_start_ms,
BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_ms);
add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms,
BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_ms);
add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms,
BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_ms);
add_builtin_function ("__builtin_sysv_va_start", fnvoid_va_start_sysv,
BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_sysv);
add_builtin_function ("__builtin_sysv_va_end", fnvoid_va_end_sysv,
BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_sysv);
add_builtin_function ("__builtin_sysv_va_copy", fnvoid_va_copy_sysv,
BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_sysv);
}
static void
ix86_register_float16_builtin_type (void)
{
/* Provide the _Float16 type and float16_type_node if needed so that
it can be used in AVX512FP16 intrinsics and builtins. */
if (!float16_type_node)
{
ix86_float16_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (ix86_float16_type_node) = 16;
SET_TYPE_MODE (ix86_float16_type_node, HFmode);
layout_type (ix86_float16_type_node);
}
else
ix86_float16_type_node = float16_type_node;
if (!maybe_get_identifier ("_Float16") && TARGET_SSE2)
lang_hooks.types.register_builtin_type (ix86_float16_type_node,
"_Float16");
}
static void
ix86_init_builtin_types (void)
{
tree float80_type_node, const_string_type_node;
/* The __float80 type. */
float80_type_node = long_double_type_node;
if (TYPE_MODE (float80_type_node) != XFmode)
{
if (float64x_type_node != NULL_TREE
&& TYPE_MODE (float64x_type_node) == XFmode)
float80_type_node = float64x_type_node;
else
{
/* The __float80 type. */
float80_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (float80_type_node) = 80;
layout_type (float80_type_node);
}
}
lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
/* The __float128 type. The node has already been created as
_Float128, so we only need to register the __float128 name for
it. */
lang_hooks.types.register_builtin_type (float128_type_node, "__float128");
ix86_register_float16_builtin_type ();
const_string_type_node
= build_pointer_type (build_qualified_type
(char_type_node, TYPE_QUAL_CONST));
/* This macro is built by i386-builtin-types.awk. */
DEFINE_BUILTIN_PRIMITIVE_TYPES;
}
void
ix86_init_builtins (void)
{
tree ftype, decl;
ix86_init_builtin_types ();
/* Builtins to get CPU type and features. */
ix86_init_platform_type_builtins ();
/* TFmode support builtins. */
def_builtin_const (0, 0, "__builtin_infq",
FLOAT128_FTYPE_VOID, IX86_BUILTIN_INFQ);
def_builtin_const (0, 0, "__builtin_huge_valq",
FLOAT128_FTYPE_VOID, IX86_BUILTIN_HUGE_VALQ);
ftype = ix86_get_builtin_func_type (FLOAT128_FTYPE_CONST_STRING);
decl = add_builtin_function ("__builtin_nanq", ftype, IX86_BUILTIN_NANQ,
BUILT_IN_MD, "nanq", NULL_TREE);
TREE_READONLY (decl) = 1;
ix86_builtins[(int) IX86_BUILTIN_NANQ] = decl;
decl = add_builtin_function ("__builtin_nansq", ftype, IX86_BUILTIN_NANSQ,
BUILT_IN_MD, "nansq", NULL_TREE);
TREE_READONLY (decl) = 1;
ix86_builtins[(int) IX86_BUILTIN_NANSQ] = decl;
/* We will expand them to normal call if SSE isn't available since
they are used by libgcc. */
ftype = ix86_get_builtin_func_type (FLOAT128_FTYPE_FLOAT128);
decl = add_builtin_function ("__builtin_fabsq", ftype, IX86_BUILTIN_FABSQ,
BUILT_IN_MD, "__fabstf2", NULL_TREE);
TREE_READONLY (decl) = 1;
ix86_builtins[(int) IX86_BUILTIN_FABSQ] = decl;
ftype = ix86_get_builtin_func_type (FLOAT128_FTYPE_FLOAT128_FLOAT128);
decl = add_builtin_function ("__builtin_copysignq", ftype,
IX86_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
"__copysigntf3", NULL_TREE);
TREE_READONLY (decl) = 1;
ix86_builtins[(int) IX86_BUILTIN_COPYSIGNQ] = decl;
ix86_init_tm_builtins ();
ix86_init_mmx_sse_builtins ();
if (TARGET_LP64)
ix86_init_builtins_va_builtins_abi ();
#ifdef SUBTARGET_INIT_BUILTINS
SUBTARGET_INIT_BUILTINS;
#endif
}
/* Return the ix86 builtin for CODE. */
tree
ix86_builtin_decl (unsigned code, bool)
{
if (code >= IX86_BUILTIN_MAX)
return error_mark_node;
return ix86_builtins[code];
}
/* This returns the target-specific builtin with code CODE if
current_function_decl has visibility on this builtin, which is checked
using isa flags. Returns NULL_TREE otherwise. */
static tree ix86_get_builtin (enum ix86_builtins code)
{
struct cl_target_option *opts;
tree target_tree = NULL_TREE;
/* Determine the isa flags of current_function_decl. */
if (current_function_decl)
target_tree = DECL_FUNCTION_SPECIFIC_TARGET (current_function_decl);
if (target_tree == NULL)
target_tree = target_option_default_node;
opts = TREE_TARGET_OPTION (target_tree);
if ((ix86_builtins_isa[(int) code].isa & opts->x_ix86_isa_flags)
|| (ix86_builtins_isa[(int) code].isa2 & opts->x_ix86_isa_flags2))
return ix86_builtin_decl (code, true);
else
return NULL_TREE;
}
/* Vectorization library interface and handlers. */
tree (*ix86_veclib_handler) (combined_fn, tree, tree);
/* Returns a function decl for a vectorized version of the combined function
with combined_fn code FN and the result vector type TYPE, or NULL_TREE
if it is not available. */
tree
ix86_builtin_vectorized_function (unsigned int fn, tree type_out,
tree type_in)
{
machine_mode in_mode, out_mode;
int in_n, out_n;
if (TREE_CODE (type_out) != VECTOR_TYPE
|| TREE_CODE (type_in) != VECTOR_TYPE)
return NULL_TREE;
out_mode = TYPE_MODE (TREE_TYPE (type_out));
out_n = TYPE_VECTOR_SUBPARTS (type_out);
in_mode = TYPE_MODE (TREE_TYPE (type_in));
in_n = TYPE_VECTOR_SUBPARTS (type_in);
switch (fn)
{
CASE_CFN_EXP2:
if (out_mode == SFmode && in_mode == SFmode)
{
if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_EXP2PS);
}
break;
CASE_CFN_IFLOOR:
CASE_CFN_LFLOOR:
CASE_CFN_LLFLOOR:
/* The round insn does not trap on denormals. */
if (flag_trapping_math || !TARGET_SSE4_1)
break;
if (out_mode == SImode && in_mode == DFmode)
{
if (out_n == 4 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_FLOORPD_VEC_PACK_SFIX);
else if (out_n == 8 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_FLOORPD_VEC_PACK_SFIX256);
else if (out_n == 16 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_FLOORPD_VEC_PACK_SFIX512);
}
if (out_mode == SImode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_FLOORPS_SFIX);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_FLOORPS_SFIX256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_FLOORPS_SFIX512);
}
break;
CASE_CFN_ICEIL:
CASE_CFN_LCEIL:
CASE_CFN_LLCEIL:
/* The round insn does not trap on denormals. */
if (flag_trapping_math || !TARGET_SSE4_1)
break;
if (out_mode == SImode && in_mode == DFmode)
{
if (out_n == 4 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_CEILPD_VEC_PACK_SFIX);
else if (out_n == 8 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_CEILPD_VEC_PACK_SFIX256);
else if (out_n == 16 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_CEILPD_VEC_PACK_SFIX512);
}
if (out_mode == SImode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_CEILPS_SFIX);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_CEILPS_SFIX256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_CEILPS_SFIX512);
}
break;
CASE_CFN_IRINT:
CASE_CFN_LRINT:
CASE_CFN_LLRINT:
if (out_mode == SImode && in_mode == DFmode)
{
if (out_n == 4 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_VEC_PACK_SFIX);
else if (out_n == 8 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_VEC_PACK_SFIX256);
else if (out_n == 16 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_VEC_PACK_SFIX512);
}
if (out_mode == SImode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_CVTPS2DQ);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_CVTPS2DQ256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_CVTPS2DQ512);
}
break;
CASE_CFN_IROUND:
CASE_CFN_LROUND:
CASE_CFN_LLROUND:
/* The round insn does not trap on denormals. */
if (flag_trapping_math || !TARGET_SSE4_1)
break;
if (out_mode == SImode && in_mode == DFmode)
{
if (out_n == 4 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_ROUNDPD_AZ_VEC_PACK_SFIX);
else if (out_n == 8 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_ROUNDPD_AZ_VEC_PACK_SFIX256);
else if (out_n == 16 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_ROUNDPD_AZ_VEC_PACK_SFIX512);
}
if (out_mode == SImode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_ROUNDPS_AZ_SFIX);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_ROUNDPS_AZ_SFIX256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_ROUNDPS_AZ_SFIX512);
}
break;
CASE_CFN_FLOOR:
/* The round insn does not trap on denormals. */
if (flag_trapping_math || !TARGET_SSE4_1)
break;
if (out_mode == DFmode && in_mode == DFmode)
{
if (out_n == 2 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_FLOORPD);
else if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_FLOORPD256);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_FLOORPD512);
}
if (out_mode == SFmode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_FLOORPS);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_FLOORPS256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_FLOORPS512);
}
if (out_mode == HFmode && in_mode == HFmode)
{
/* V8HF/V16HF is supported in ix86_vector_mode_supported_p
under TARGET_AVX512FP16, TARGET_AVX512VL is needed here. */
if (out_n < 32 && !TARGET_AVX512VL)
break;
if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_FLOORPH);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_FLOORPH256);
else if (out_n == 32 && in_n == 32)
return ix86_get_builtin (IX86_BUILTIN_FLOORPH512);
}
break;
CASE_CFN_CEIL:
/* The round insn does not trap on denormals. */
if (flag_trapping_math || !TARGET_SSE4_1)
break;
if (out_mode == DFmode && in_mode == DFmode)
{
if (out_n == 2 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_CEILPD);
else if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_CEILPD256);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_CEILPD512);
}
if (out_mode == SFmode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_CEILPS);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_CEILPS256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_CEILPS512);
}
if (out_mode == HFmode && in_mode == HFmode)
{
/* V8HF/V16HF is supported in ix86_vector_mode_supported_p
under TARGET_AVX512FP16, TARGET_AVX512VL is needed here. */
if (out_n < 32 && !TARGET_AVX512VL)
break;
if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_CEILPH);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_CEILPH256);
else if (out_n == 32 && in_n == 32)
return ix86_get_builtin (IX86_BUILTIN_CEILPH512);
}
break;
CASE_CFN_TRUNC:
/* The round insn does not trap on denormals. */
if (flag_trapping_math || !TARGET_SSE4_1)
break;
if (out_mode == DFmode && in_mode == DFmode)
{
if (out_n == 2 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPD);
else if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPD256);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPD512);
}
if (out_mode == SFmode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPS);
else if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPS256);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPS512);
}
if (out_mode == HFmode && in_mode == HFmode)
{
/* V8HF/V16HF is supported in ix86_vector_mode_supported_p
under TARGET_AVX512FP16, TARGET_AVX512VL is needed here. */
if (out_n < 32 && !TARGET_AVX512VL)
break;
if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPH);
else if (out_n == 16 && in_n == 16)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPH256);
else if (out_n == 32 && in_n == 32)
return ix86_get_builtin (IX86_BUILTIN_TRUNCPH512);
}
break;
CASE_CFN_FMA:
if (out_mode == DFmode && in_mode == DFmode)
{
if (out_n == 2 && in_n == 2)
return ix86_get_builtin (IX86_BUILTIN_VFMADDPD);
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_VFMADDPD256);
}
if (out_mode == SFmode && in_mode == SFmode)
{
if (out_n == 4 && in_n == 4)
return ix86_get_builtin (IX86_BUILTIN_VFMADDPS);
if (out_n == 8 && in_n == 8)
return ix86_get_builtin (IX86_BUILTIN_VFMADDPS256);
}
break;
default:
break;
}
/* Dispatch to a handler for a vectorization library. */
if (ix86_veclib_handler)
return ix86_veclib_handler (combined_fn (fn), type_out, type_in);
return NULL_TREE;
}
/* Returns a decl of a function that implements gather load with
memory type MEM_VECTYPE and index type INDEX_VECTYPE and SCALE.
Return NULL_TREE if it is not available. */
tree
ix86_vectorize_builtin_gather (const_tree mem_vectype,
const_tree index_type, int scale)
{
bool si;
enum ix86_builtins code;
if (! TARGET_AVX2
|| (known_eq (TYPE_VECTOR_SUBPARTS (mem_vectype), 2u)
? !TARGET_USE_GATHER_2PARTS
: (known_eq (TYPE_VECTOR_SUBPARTS (mem_vectype), 4u)
? !TARGET_USE_GATHER_4PARTS
: !TARGET_USE_GATHER)))
return NULL_TREE;
if ((TREE_CODE (index_type) != INTEGER_TYPE
&& !POINTER_TYPE_P (index_type))
|| (TYPE_MODE (index_type) != SImode
&& TYPE_MODE (index_type) != DImode))
return NULL_TREE;
if (TYPE_PRECISION (index_type) > POINTER_SIZE)
return NULL_TREE;
/* v*gather* insn sign extends index to pointer mode. */
if (TYPE_PRECISION (index_type) < POINTER_SIZE
&& TYPE_UNSIGNED (index_type))
return NULL_TREE;
if (scale <= 0
|| scale > 8
|| (scale & (scale - 1)) != 0)
return NULL_TREE;
si = TYPE_MODE (index_type) == SImode;
switch (TYPE_MODE (mem_vectype))
{
case E_V2DFmode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3SIV2DF : IX86_BUILTIN_GATHER3DIV2DF;
else
code = si ? IX86_BUILTIN_GATHERSIV2DF : IX86_BUILTIN_GATHERDIV2DF;
break;
case E_V4DFmode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3ALTSIV4DF : IX86_BUILTIN_GATHER3DIV4DF;
else
code = si ? IX86_BUILTIN_GATHERALTSIV4DF : IX86_BUILTIN_GATHERDIV4DF;
break;
case E_V2DImode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3SIV2DI : IX86_BUILTIN_GATHER3DIV2DI;
else
code = si ? IX86_BUILTIN_GATHERSIV2DI : IX86_BUILTIN_GATHERDIV2DI;
break;
case E_V4DImode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3ALTSIV4DI : IX86_BUILTIN_GATHER3DIV4DI;
else
code = si ? IX86_BUILTIN_GATHERALTSIV4DI : IX86_BUILTIN_GATHERDIV4DI;
break;
case E_V4SFmode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3SIV4SF : IX86_BUILTIN_GATHER3DIV4SF;
else
code = si ? IX86_BUILTIN_GATHERSIV4SF : IX86_BUILTIN_GATHERDIV4SF;
break;
case E_V8SFmode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3SIV8SF : IX86_BUILTIN_GATHER3ALTDIV8SF;
else
code = si ? IX86_BUILTIN_GATHERSIV8SF : IX86_BUILTIN_GATHERALTDIV8SF;
break;
case E_V4SImode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3SIV4SI : IX86_BUILTIN_GATHER3DIV4SI;
else
code = si ? IX86_BUILTIN_GATHERSIV4SI : IX86_BUILTIN_GATHERDIV4SI;
break;
case E_V8SImode:
if (TARGET_AVX512VL)
code = si ? IX86_BUILTIN_GATHER3SIV8SI : IX86_BUILTIN_GATHER3ALTDIV8SI;
else
code = si ? IX86_BUILTIN_GATHERSIV8SI : IX86_BUILTIN_GATHERALTDIV8SI;
break;
case E_V8DFmode:
if (TARGET_AVX512F)
code = si ? IX86_BUILTIN_GATHER3ALTSIV8DF : IX86_BUILTIN_GATHER3DIV8DF;
else
return NULL_TREE;
break;
case E_V8DImode:
if (TARGET_AVX512F)
code = si ? IX86_BUILTIN_GATHER3ALTSIV8DI : IX86_BUILTIN_GATHER3DIV8DI;
else
return NULL_TREE;
break;
case E_V16SFmode:
if (TARGET_AVX512F)
code = si ? IX86_BUILTIN_GATHER3SIV16SF : IX86_BUILTIN_GATHER3ALTDIV16SF;
else
return NULL_TREE;
break;
case E_V16SImode:
if (TARGET_AVX512F)
code = si ? IX86_BUILTIN_GATHER3SIV16SI : IX86_BUILTIN_GATHER3ALTDIV16SI;
else
return NULL_TREE;
break;
default:
return NULL_TREE;
}
return ix86_get_builtin (code);
}
/* Returns a code for a target-specific builtin that implements
reciprocal of the function, or NULL_TREE if not available. */
tree
ix86_builtin_reciprocal (tree fndecl)
{
enum ix86_builtins fn_code
= (enum ix86_builtins) DECL_MD_FUNCTION_CODE (fndecl);
switch (fn_code)
{
/* Vectorized version of sqrt to rsqrt conversion. */
case IX86_BUILTIN_SQRTPS_NR:
return ix86_get_builtin (IX86_BUILTIN_RSQRTPS_NR);
case IX86_BUILTIN_SQRTPS_NR256:
return ix86_get_builtin (IX86_BUILTIN_RSQRTPS_NR256);
default:
return NULL_TREE;
}
}
/* This parses the attribute arguments to target in DECL and determines
the right builtin to use to match the platform specification.
It returns the priority value for this version decl. If PREDICATE_LIST
is not NULL, it stores the list of cpu features that need to be checked
before dispatching this function. */
unsigned int
get_builtin_code_for_version (tree decl, tree *predicate_list)
{
tree attrs;
struct cl_target_option cur_target;
tree target_node;
struct cl_target_option *new_target;
const char *arg_str = NULL;
const char *attrs_str = NULL;
char *tok_str = NULL;
char *token;
enum feature_priority priority = P_NONE;
static unsigned int NUM_FEATURES
= sizeof (isa_names_table) / sizeof (_isa_names_table);
unsigned int i;
tree predicate_chain = NULL_TREE;
tree predicate_decl, predicate_arg;
attrs = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
gcc_assert (attrs != NULL);
attrs = TREE_VALUE (TREE_VALUE (attrs));
gcc_assert (TREE_CODE (attrs) == STRING_CST);
attrs_str = TREE_STRING_POINTER (attrs);
/* Return priority zero for default function. */
if (strcmp (attrs_str, "default") == 0)
return 0;
/* Handle arch= if specified. For priority, set it to be 1 more than
the best instruction set the processor can handle. For instance, if
there is a version for atom and a version for ssse3 (the highest ISA
priority for atom), the atom version must be checked for dispatch
before the ssse3 version. */
if (strstr (attrs_str, "arch=") != NULL)
{
cl_target_option_save (&cur_target, &global_options,
&global_options_set);
target_node
= ix86_valid_target_attribute_tree (decl, attrs, &global_options,
&global_options_set, 0);
gcc_assert (target_node);
if (target_node == error_mark_node)
return 0;
new_target = TREE_TARGET_OPTION (target_node);
gcc_assert (new_target);
enum ix86_builtins builtin_fn = IX86_BUILTIN_CPU_IS;
/* Special case x86-64 micro-level architectures. */
const char *arch_name = attrs_str + strlen ("arch=");
if (startswith (arch_name, "x86-64"))
{
arg_str = arch_name;
builtin_fn = IX86_BUILTIN_CPU_SUPPORTS;
if (strcmp (arch_name, "x86-64") == 0)
priority = P_X86_64_BASELINE;
else if (strcmp (arch_name, "x86-64-v2") == 0)
priority = P_X86_64_V2;
else if (strcmp (arch_name, "x86-64-v3") == 0)
priority = P_X86_64_V3;
else if (strcmp (arch_name, "x86-64-v4") == 0)
priority = P_X86_64_V4;
}
else if (new_target->arch_specified && new_target->arch > 0)
for (i = 0; i < pta_size; i++)
if (processor_alias_table[i].processor == new_target->arch)
{
const pta *arch_info = &processor_alias_table[i];
switch (arch_info->priority)
{
default:
arg_str = arch_info->name;
priority = arch_info->priority;
break;
case P_PROC_DYNAMIC:
switch (new_target->arch)
{
case PROCESSOR_NEHALEM:
if (TARGET_PCLMUL_P (new_target->x_ix86_isa_flags))
{
arg_str = "westmere";
priority = P_PCLMUL;
}
else
{
/* We translate "arch=corei7" and "arch=nehalem"
to "corei7" so that it will be mapped to
M_INTEL_COREI7 as cpu type to cover all
M_INTEL_COREI7_XXXs. */
arg_str = "corei7";
priority = P_PROC_SSE4_2;
}
break;
case PROCESSOR_SANDYBRIDGE:
if (TARGET_F16C_P (new_target->x_ix86_isa_flags))
arg_str = "ivybridge";
else
arg_str = "sandybridge";
priority = P_PROC_AVX;
break;
case PROCESSOR_HASWELL:
if (TARGET_ADX_P (new_target->x_ix86_isa_flags))
arg_str = "broadwell";
else
arg_str = "haswell";
priority = P_PROC_AVX2;
break;
case PROCESSOR_AMDFAM10:
arg_str = "amdfam10h";
priority = P_PROC_SSE4_A;
break;
default:
gcc_unreachable ();
}
break;
case P_NONE:
break;
}
break;
}
cl_target_option_restore (&global_options, &global_options_set,
&cur_target);
if (predicate_list && arg_str == NULL)
{
error_at (DECL_SOURCE_LOCATION (decl),
"no dispatcher found for the versioning attributes");
return 0;
}
if (predicate_list)
{
predicate_decl = ix86_builtins [(int) builtin_fn];
/* For a C string literal the length includes the trailing NULL. */
predicate_arg = build_string_literal (strlen (arg_str) + 1, arg_str);
predicate_chain = tree_cons (predicate_decl, predicate_arg,
predicate_chain);
}
}
/* Process feature name. */
tok_str = (char *) xmalloc (strlen (attrs_str) + 1);
strcpy (tok_str, attrs_str);
token = strtok (tok_str, ",");
predicate_decl = ix86_builtins [(int) IX86_BUILTIN_CPU_SUPPORTS];
while (token != NULL)
{
/* Do not process "arch=" */
if (startswith (token, "arch="))
{
token = strtok (NULL, ",");
continue;
}
for (i = 0; i < NUM_FEATURES; ++i)
{
if (strcmp (token, isa_names_table[i].name) == 0)
{
if (predicate_list)
{
predicate_arg = build_string_literal (
strlen (isa_names_table[i].name) + 1,
isa_names_table[i].name);
predicate_chain = tree_cons (predicate_decl, predicate_arg,
predicate_chain);
}
/* Find the maximum priority feature. */
if (isa_names_table[i].priority > priority)
priority = isa_names_table[i].priority;
break;
}
}
if (predicate_list && priority == P_NONE)
{
error_at (DECL_SOURCE_LOCATION (decl),
"ISA %qs is not supported in % attribute, "
"use % syntax", token);
return 0;
}
token = strtok (NULL, ",");
}
free (tok_str);
if (predicate_list && predicate_chain == NULL_TREE)
{
error_at (DECL_SOURCE_LOCATION (decl),
"no dispatcher found for the versioning attributes: %s",
attrs_str);
return 0;
}
else if (predicate_list)
{
predicate_chain = nreverse (predicate_chain);
*predicate_list = predicate_chain;
}
return priority;
}
/* This builds the processor_model struct type defined in
libgcc/config/i386/cpuinfo.c */
static tree
build_processor_model_struct (void)
{
const char *field_name[] = {"__cpu_vendor", "__cpu_type", "__cpu_subtype",
"__cpu_features"};
tree field = NULL_TREE, field_chain = NULL_TREE;
int i;
tree type = make_node (RECORD_TYPE);
/* The first 3 fields are unsigned int. */
for (i = 0; i < 3; ++i)
{
field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
get_identifier (field_name[i]), unsigned_type_node);
if (field_chain != NULL_TREE)
DECL_CHAIN (field) = field_chain;
field_chain = field;
}
/* The last field is an array of unsigned integers of size one. */
field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
get_identifier (field_name[3]),
build_array_type (unsigned_type_node,
build_index_type (size_one_node)));
if (field_chain != NULL_TREE)
DECL_CHAIN (field) = field_chain;
field_chain = field;
finish_builtin_struct (type, "__processor_model", field_chain, NULL_TREE);
return type;
}
/* Returns a extern, comdat VAR_DECL of type TYPE and name NAME. */
static tree
make_var_decl (tree type, const char *name)
{
tree new_decl;
new_decl = build_decl (UNKNOWN_LOCATION,
VAR_DECL,
get_identifier(name),
type);
DECL_EXTERNAL (new_decl) = 1;
TREE_STATIC (new_decl) = 1;
TREE_PUBLIC (new_decl) = 1;
DECL_INITIAL (new_decl) = 0;
DECL_ARTIFICIAL (new_decl) = 0;
DECL_PRESERVE_P (new_decl) = 1;
make_decl_one_only (new_decl, DECL_ASSEMBLER_NAME (new_decl));
assemble_variable (new_decl, 0, 0, 0);
return new_decl;
}
static GTY(()) tree ix86_cpu_model_type_node;
static GTY(()) tree ix86_cpu_model_var;
static GTY(()) tree ix86_cpu_features2_type_node;
static GTY(()) tree ix86_cpu_features2_var;
/* FNDECL is a __builtin_cpu_is or a __builtin_cpu_supports call that is folded
into an integer defined in libgcc/config/i386/cpuinfo.c */
tree
fold_builtin_cpu (tree fndecl, tree *args)
{
unsigned int i;
enum ix86_builtins fn_code
= (enum ix86_builtins) DECL_MD_FUNCTION_CODE (fndecl);
tree param_string_cst = NULL;
if (ix86_cpu_model_var == nullptr)
{
/* Build a single __cpu_model variable for all references to
__cpu_model so that GIMPLE level optimizers can CSE the loads
of __cpu_model and optimize bit-operations properly. */
ix86_cpu_model_type_node = build_processor_model_struct ();
ix86_cpu_model_var = make_var_decl (ix86_cpu_model_type_node,
"__cpu_model");
varpool_node::add (ix86_cpu_model_var);
}
gcc_assert ((args != NULL) && (*args != NULL));
param_string_cst = *args;
while (param_string_cst
&& TREE_CODE (param_string_cst) != STRING_CST)
{
/* *args must be a expr that can contain other EXPRS leading to a
STRING_CST. */
if (!EXPR_P (param_string_cst))
{
error ("parameter to builtin must be a string constant or literal");
return integer_zero_node;
}
param_string_cst = TREE_OPERAND (EXPR_CHECK (param_string_cst), 0);
}
gcc_assert (param_string_cst);
if (fn_code == IX86_BUILTIN_CPU_IS)
{
tree ref;
tree field;
tree final;
unsigned int field_val = 0;
for (i = 0; i < num_arch_names; i++)
if (processor_alias_table[i].model != 0
&& strcmp (processor_alias_table[i].name,
TREE_STRING_POINTER (param_string_cst)) == 0)
break;
if (i == num_arch_names)
{
error ("parameter to builtin not valid: %s",
TREE_STRING_POINTER (param_string_cst));
return integer_zero_node;
}
field = TYPE_FIELDS (ix86_cpu_model_type_node);
field_val = processor_alias_table[i].model;
/* CPU types are stored in the next field. */
if (field_val > M_CPU_TYPE_START
&& field_val < M_CPU_SUBTYPE_START)
{
field = DECL_CHAIN (field);
field_val -= M_CPU_TYPE_START;
}
/* CPU subtypes are stored in the next field. */
if (field_val > M_CPU_SUBTYPE_START)
{
field = DECL_CHAIN ( DECL_CHAIN (field));
field_val -= M_CPU_SUBTYPE_START;
}
/* Get the appropriate field in __cpu_model. */
ref = build3 (COMPONENT_REF, TREE_TYPE (field), ix86_cpu_model_var,
field, NULL_TREE);
/* Check the value. */
final = build2 (EQ_EXPR, unsigned_type_node, ref,
build_int_cstu (unsigned_type_node, field_val));
return build1 (NOP_EXPR, integer_type_node, final);
}
else if (fn_code == IX86_BUILTIN_CPU_SUPPORTS)
{
tree ref;
tree array_elt;
tree field;
tree final;
unsigned int field_val = 0;
unsigned int NUM_ISA_NAMES
= sizeof (isa_names_table) / sizeof (struct _isa_names_table);
for (i = 0; i < NUM_ISA_NAMES; i++)
if (strcmp (isa_names_table[i].name,
TREE_STRING_POINTER (param_string_cst)) == 0)
break;
if (i == NUM_ISA_NAMES)
{
error ("parameter to builtin not valid: %s",
TREE_STRING_POINTER (param_string_cst));
return integer_zero_node;
}
unsigned feature = isa_names_table[i].feature;
if (feature >= INT_TYPE_SIZE)
{
if (ix86_cpu_features2_var == nullptr)
{
/* Build a single __cpu_features2 variable for all
references to __cpu_features2 so that GIMPLE level
optimizers can CSE the loads of __cpu_features2 and
optimize bit-operations properly. */
tree index_type
= build_index_type (size_int (SIZE_OF_CPU_FEATURES));
ix86_cpu_features2_type_node
= build_array_type (unsigned_type_node, index_type);
ix86_cpu_features2_var
= make_var_decl (ix86_cpu_features2_type_node,
"__cpu_features2");
varpool_node::add (ix86_cpu_features2_var);
}
/* Skip __cpu_features[0]. */
feature -= INT_TYPE_SIZE;
tree index = size_int (feature / INT_TYPE_SIZE);
feature = feature % INT_TYPE_SIZE;
array_elt = build4 (ARRAY_REF, unsigned_type_node,
ix86_cpu_features2_var,
index, NULL_TREE, NULL_TREE);
/* Return __cpu_features2[index] & field_val */
}
else
{
field = TYPE_FIELDS (ix86_cpu_model_type_node);
/* Get the last field, which is __cpu_features. */
while (DECL_CHAIN (field))
field = DECL_CHAIN (field);
/* Get the appropriate field: __cpu_model.__cpu_features */
ref = build3 (COMPONENT_REF, TREE_TYPE (field), ix86_cpu_model_var,
field, NULL_TREE);
/* Access the 0th element of __cpu_features array. */
array_elt = build4 (ARRAY_REF, unsigned_type_node, ref,
integer_zero_node, NULL_TREE, NULL_TREE);
/* Return __cpu_model.__cpu_features[0] & field_val */
}
field_val = 1U << feature;
final = build2 (BIT_AND_EXPR, unsigned_type_node, array_elt,
build_int_cstu (unsigned_type_node, field_val));
if (feature == INT_TYPE_SIZE - 1)
return build2 (NE_EXPR, integer_type_node, final,
build_int_cst (unsigned_type_node, 0));
else
return build1 (NOP_EXPR, integer_type_node, final);
}
gcc_unreachable ();
}
#include "gt-i386-builtins.h"