1225 lines
38 KiB
C++
1225 lines
38 KiB
C++
/* d-builtins.cc -- GCC builtins support for D.
|
|
Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
|
|
#include "dmd/attrib.h"
|
|
#include "dmd/aggregate.h"
|
|
#include "dmd/cond.h"
|
|
#include "dmd/declaration.h"
|
|
#include "dmd/expression.h"
|
|
#include "dmd/identifier.h"
|
|
#include "dmd/module.h"
|
|
#include "dmd/mtype.h"
|
|
#include "dmd/target.h"
|
|
|
|
#include "tree.h"
|
|
#include "fold-const.h"
|
|
#include "diagnostic.h"
|
|
#include "langhooks.h"
|
|
#include "target.h"
|
|
#include "common/common-target.h"
|
|
#include "stringpool.h"
|
|
#include "stor-layout.h"
|
|
|
|
#include "d-tree.h"
|
|
#include "d-target.h"
|
|
|
|
|
|
static GTY(()) vec <tree, va_gc> *gcc_builtins_functions = NULL;
|
|
static GTY(()) vec <tree, va_gc> *gcc_builtins_libfuncs = NULL;
|
|
static GTY(()) vec <tree, va_gc> *gcc_builtins_types = NULL;
|
|
|
|
/* Record built-in types and their associated decls for re-use when
|
|
generating the `gcc.builtins' module. */
|
|
|
|
struct builtin_data
|
|
{
|
|
Type *dtype;
|
|
tree ctype;
|
|
Dsymbol *dsym;
|
|
|
|
builtin_data (Type *t, tree c, Dsymbol *d = NULL)
|
|
: dtype(t), ctype(c), dsym(d)
|
|
{ }
|
|
};
|
|
|
|
static vec <builtin_data> builtin_converted_decls;
|
|
|
|
/* Build D frontend type from tree TYPE type given. This will set the
|
|
back-end type symbol directly for complex types to save build_ctype()
|
|
the work. For other types, it is not useful or will cause errors, such
|
|
as casting from `C char' to `D char', which also means that `char *`
|
|
needs to be specially handled. */
|
|
|
|
Type *
|
|
build_frontend_type (tree type)
|
|
{
|
|
Type *dtype;
|
|
MOD mod = 0;
|
|
|
|
if (TYPE_READONLY (type))
|
|
mod |= MODconst;
|
|
if (TYPE_VOLATILE (type))
|
|
mod |= MODshared;
|
|
|
|
/* If we've seen the type before, re-use the converted decl. */
|
|
for (size_t i = 0; i < builtin_converted_decls.length (); ++i)
|
|
{
|
|
tree t = builtin_converted_decls[i].ctype;
|
|
if (TYPE_MAIN_VARIANT (t) == TYPE_MAIN_VARIANT (type))
|
|
return builtin_converted_decls[i].dtype;
|
|
}
|
|
|
|
switch (TREE_CODE (type))
|
|
{
|
|
case POINTER_TYPE:
|
|
dtype = build_frontend_type (TREE_TYPE (type));
|
|
if (dtype)
|
|
{
|
|
/* Check for char * first. Needs to be done for chars/string. */
|
|
if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
|
|
return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
|
|
|
|
if (dtype->ty == Tfunction)
|
|
return (TypePointer::create (dtype))->addMod (mod);
|
|
|
|
return dtype->pointerTo ()->addMod (mod);
|
|
}
|
|
break;
|
|
|
|
case REFERENCE_TYPE:
|
|
dtype = build_frontend_type (TREE_TYPE (type));
|
|
if (dtype)
|
|
{
|
|
/* Want to assign ctype directly so that the REFERENCE_TYPE code
|
|
can be turned into as an `inout' argument. Can't use pointerTo(),
|
|
because the returned Type is shared. */
|
|
dtype = (TypePointer::create (dtype))->addMod (mod);
|
|
dtype->ctype = type;
|
|
builtin_converted_decls.safe_push (builtin_data (dtype, type));
|
|
return dtype;
|
|
}
|
|
break;
|
|
|
|
case BOOLEAN_TYPE:
|
|
/* Should be no need for size checking. */
|
|
return Type::tbool->addMod (mod);
|
|
|
|
case INTEGER_TYPE:
|
|
{
|
|
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
|
|
bool unsignedp = TYPE_UNSIGNED (type);
|
|
|
|
/* For now, skip support for cent/ucent until the frontend
|
|
has better support for handling it. */
|
|
for (size_t i = Tint8; i <= Tuns64; i++)
|
|
{
|
|
dtype = Type::basic[i];
|
|
|
|
/* Search for type matching size and signedness. */
|
|
if (unsignedp != dtype->isunsigned ()
|
|
|| size != dtype->size ())
|
|
continue;
|
|
|
|
return dtype->addMod (mod);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case REAL_TYPE:
|
|
{
|
|
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
|
|
|
|
for (size_t i = Tfloat32; i <= Tfloat80; i++)
|
|
{
|
|
dtype = Type::basic[i];
|
|
|
|
/* Search for type matching size. */
|
|
if (dtype->size () != size)
|
|
continue;
|
|
|
|
return dtype->addMod (mod);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case COMPLEX_TYPE:
|
|
{
|
|
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
|
|
for (size_t i = Tcomplex32; i <= Tcomplex80; i++)
|
|
{
|
|
dtype = Type::basic[i];
|
|
|
|
/* Search for type matching size. */
|
|
if (dtype->size () != size)
|
|
continue;
|
|
|
|
return dtype->addMod (mod);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case VOID_TYPE:
|
|
return Type::tvoid->addMod (mod);
|
|
|
|
case ARRAY_TYPE:
|
|
dtype = build_frontend_type (TREE_TYPE (type));
|
|
if (dtype)
|
|
{
|
|
tree index = TYPE_DOMAIN (type);
|
|
tree ub = TYPE_MAX_VALUE (index);
|
|
tree lb = TYPE_MIN_VALUE (index);
|
|
|
|
tree length = fold_build2 (MINUS_EXPR, TREE_TYPE (lb), ub, lb);
|
|
length = size_binop (PLUS_EXPR, size_one_node,
|
|
convert (sizetype, length));
|
|
|
|
dtype = dtype->sarrayOf (TREE_INT_CST_LOW (length))->addMod (mod);
|
|
builtin_converted_decls.safe_push (builtin_data (dtype, type));
|
|
return dtype;
|
|
}
|
|
break;
|
|
|
|
case VECTOR_TYPE:
|
|
{
|
|
unsigned HOST_WIDE_INT nunits;
|
|
if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&nunits))
|
|
break;
|
|
|
|
dtype = build_frontend_type (TREE_TYPE (type));
|
|
if (!dtype)
|
|
break;
|
|
|
|
dtype = dtype->sarrayOf (nunits)->addMod (mod);
|
|
if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
|
|
break;
|
|
|
|
dtype = (TypeVector::create (dtype))->addMod (mod);
|
|
builtin_converted_decls.safe_push (builtin_data (dtype, type));
|
|
return dtype;
|
|
}
|
|
|
|
case RECORD_TYPE:
|
|
{
|
|
Identifier *ident = TYPE_IDENTIFIER (type) ?
|
|
Identifier::idPool (IDENTIFIER_POINTER (TYPE_IDENTIFIER (type))) : NULL;
|
|
|
|
/* Neither the `object' and `gcc.builtins' modules will not exist when
|
|
this is called. Use a stub `object' module parent in the meantime.
|
|
If `gcc.builtins' is later imported, the parent will be overridden
|
|
with the correct module symbol. */
|
|
static Identifier *object = Identifier::idPool ("object");
|
|
static Module *stubmod = Module::create ("object.d", object, 0, 0);
|
|
|
|
StructDeclaration *sdecl = StructDeclaration::create (Loc (), ident,
|
|
false);
|
|
sdecl->parent = stubmod;
|
|
sdecl->structsize = int_size_in_bytes (type);
|
|
sdecl->alignsize = TYPE_ALIGN_UNIT (type);
|
|
sdecl->alignment = STRUCTALIGN_DEFAULT;
|
|
sdecl->sizeok = SIZEOKdone;
|
|
sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
|
|
sdecl->type->ctype = type;
|
|
sdecl->type->merge2 ();
|
|
|
|
/* Add both named and anonymous fields as members of the struct.
|
|
Anonymous fields still need a name in D, so call them "__pad%d". */
|
|
int anonfield_id = 0;
|
|
sdecl->members = new Dsymbols;
|
|
|
|
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
|
{
|
|
Type *ftype = build_frontend_type (TREE_TYPE (field));
|
|
if (!ftype)
|
|
{
|
|
delete sdecl->members;
|
|
return NULL;
|
|
}
|
|
|
|
Identifier *fident;
|
|
if (DECL_NAME (field) == NULL_TREE)
|
|
fident = Identifier::generateId ("__pad", anonfield_id++);
|
|
else
|
|
{
|
|
const char *name = IDENTIFIER_POINTER (DECL_NAME (field));
|
|
fident = Identifier::idPool (name);
|
|
}
|
|
|
|
VarDeclaration *vd = VarDeclaration::create (Loc (), ftype, fident,
|
|
NULL);
|
|
vd->parent = sdecl;
|
|
vd->offset = tree_to_uhwi (byte_position (field));
|
|
vd->semanticRun = PASSsemanticdone;
|
|
vd->csym = field;
|
|
sdecl->members->push (vd);
|
|
sdecl->fields.push (vd);
|
|
}
|
|
|
|
dtype = sdecl->type;
|
|
builtin_converted_decls.safe_push (builtin_data (dtype, type, sdecl));
|
|
return dtype;
|
|
}
|
|
|
|
case FUNCTION_TYPE:
|
|
dtype = build_frontend_type (TREE_TYPE (type));
|
|
if (dtype)
|
|
{
|
|
tree parms = TYPE_ARG_TYPES (type);
|
|
VarArg varargs_p = VARARGvariadic;
|
|
|
|
Parameters *args = new Parameters;
|
|
args->reserve (list_length (parms));
|
|
|
|
/* Attempt to convert all parameter types. */
|
|
for (tree parm = parms; parm != NULL_TREE; parm = TREE_CHAIN (parm))
|
|
{
|
|
tree argtype = TREE_VALUE (parm);
|
|
if (argtype == void_type_node)
|
|
{
|
|
varargs_p = VARARGnone;
|
|
break;
|
|
}
|
|
|
|
StorageClass sc = STCundefined;
|
|
if (TREE_CODE (argtype) == REFERENCE_TYPE)
|
|
{
|
|
argtype = TREE_TYPE (argtype);
|
|
sc |= STCref;
|
|
}
|
|
|
|
Type *targ = build_frontend_type (argtype);
|
|
if (!targ)
|
|
{
|
|
delete args;
|
|
return NULL;
|
|
}
|
|
|
|
args->push (Parameter::create (sc, targ, NULL, NULL, NULL));
|
|
}
|
|
|
|
/* GCC generic and placeholder built-ins are marked as variadic, yet
|
|
have no named parameters, and so can't be represented in D. */
|
|
if (args->length != 0 || varargs_p == VARARGnone)
|
|
{
|
|
dtype = TypeFunction::create (args, dtype, varargs_p, LINKc);
|
|
return dtype->addMod (mod);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Attempt to convert GCC evaluated CST to a D Frontend Expression.
|
|
LOC is the location in the source file where this CST is being evaluated.
|
|
This is used for getting the CTFE value out of a const-folded builtin,
|
|
returns NULL if it cannot convert CST. */
|
|
|
|
Expression *
|
|
d_eval_constant_expression (const Loc &loc, tree cst)
|
|
{
|
|
STRIP_TYPE_NOPS (cst);
|
|
Type *type = build_frontend_type (TREE_TYPE (cst));
|
|
|
|
if (type)
|
|
{
|
|
/* Convert our GCC CST tree into a D Expression. This seems like we are
|
|
trying too hard, as these will only be converted back to a tree again
|
|
later in the codegen pass, but satisfies the need to have GCC built-ins
|
|
CTFE-able in the frontend. */
|
|
tree_code code = TREE_CODE (cst);
|
|
if (code == COMPLEX_CST)
|
|
{
|
|
real_value re = TREE_REAL_CST (TREE_REALPART (cst));
|
|
real_value im = TREE_REAL_CST (TREE_IMAGPART (cst));
|
|
complex_t value = complex_t (ldouble (re), ldouble (im));
|
|
return ComplexExp::create (loc, value, type);
|
|
}
|
|
else if (code == INTEGER_CST)
|
|
{
|
|
dinteger_t value = TREE_INT_CST_LOW (cst);
|
|
return IntegerExp::create (loc, value, type);
|
|
}
|
|
else if (code == REAL_CST)
|
|
{
|
|
real_value value = TREE_REAL_CST (cst);
|
|
return RealExp::create (loc, ldouble (value), type);
|
|
}
|
|
else if (code == STRING_CST)
|
|
{
|
|
const void *string = TREE_STRING_POINTER (cst);
|
|
size_t len = TREE_STRING_LENGTH (cst) - 1;
|
|
return StringExp::create (loc, CONST_CAST (void *, string), len);
|
|
}
|
|
else if (code == VECTOR_CST)
|
|
{
|
|
dinteger_t nunits = VECTOR_CST_NELTS (cst).to_constant ();
|
|
Expressions *elements = new Expressions;
|
|
elements->setDim (nunits);
|
|
|
|
for (size_t i = 0; i < nunits; i++)
|
|
{
|
|
Expression *elem
|
|
= d_eval_constant_expression (loc, VECTOR_CST_ELT (cst, i));
|
|
if (elem == NULL)
|
|
return NULL;
|
|
|
|
(*elements)[i] = elem;
|
|
}
|
|
|
|
Expression *e = ArrayLiteralExp::create (loc, elements);
|
|
e->type = type->isTypeVector ()->basetype;
|
|
|
|
return VectorExp::create (loc, e, type);
|
|
}
|
|
else if (code == ADDR_EXPR)
|
|
{
|
|
/* Special handling for trees constructed by build_string_literal.
|
|
What we receive is an `&"string"[0]' expression, strip off the
|
|
outer ADDR_EXPR and ARRAY_REF to get to the underlying CST. */
|
|
tree pointee = TREE_OPERAND (cst, 0);
|
|
|
|
if (TREE_CODE (pointee) != ARRAY_REF
|
|
|| TREE_OPERAND (pointee, 1) != integer_zero_node
|
|
|| TREE_CODE (TREE_OPERAND (pointee, 0)) != STRING_CST)
|
|
return NULL;
|
|
|
|
return d_eval_constant_expression (loc, TREE_OPERAND (pointee, 0));
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Callback for TARGET_D_CPU_VERSIONS and TARGET_D_OS_VERSIONS.
|
|
Adds IDENT to the list of predefined version identifiers. */
|
|
|
|
void
|
|
d_add_builtin_version (const char* ident)
|
|
{
|
|
VersionCondition::addPredefinedGlobalIdent (ident);
|
|
}
|
|
|
|
/* Initialize the list of all the predefined version identifiers. */
|
|
|
|
void
|
|
d_init_versions (void)
|
|
{
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU");
|
|
VersionCondition::addPredefinedGlobalIdent ("D_Version2");
|
|
|
|
if (BYTES_BIG_ENDIAN)
|
|
VersionCondition::addPredefinedGlobalIdent ("BigEndian");
|
|
else
|
|
VersionCondition::addPredefinedGlobalIdent ("LittleEndian");
|
|
|
|
if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU_SjLj_Exceptions");
|
|
else if (targetm_common.except_unwind_info (&global_options) == UI_SEH)
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU_SEH_Exceptions");
|
|
else if (targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU_DWARF2_Exceptions");
|
|
|
|
if (!targetm.have_tls)
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU_EMUTLS");
|
|
|
|
if (STACK_GROWS_DOWNWARD)
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU_StackGrowsDown");
|
|
|
|
/* Should define this anyway to set us apart from the competition. */
|
|
VersionCondition::addPredefinedGlobalIdent ("GNU_InlineAsm");
|
|
|
|
/* LP64 only means 64bit pointers in D. */
|
|
if (global.params.isLP64)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_LP64");
|
|
|
|
/* Setting `global.params.cov' forces module info generation which is
|
|
not needed for the GCC coverage implementation. Instead, just
|
|
test flag_test_coverage while leaving `global.params.cov' unset. */
|
|
if (flag_test_coverage)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_Coverage");
|
|
if (flag_pic)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_PIC");
|
|
if (flag_pie)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_PIE");
|
|
|
|
if (global.params.doDocComments)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_Ddoc");
|
|
|
|
if (global.params.useUnitTests)
|
|
VersionCondition::addPredefinedGlobalIdent ("unittest");
|
|
|
|
if (global.params.useAssert == CHECKENABLEon)
|
|
VersionCondition::addPredefinedGlobalIdent ("assert");
|
|
|
|
if (global.params.useArrayBounds == CHECKENABLEoff)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks");
|
|
|
|
if (global.params.betterC)
|
|
VersionCondition::addPredefinedGlobalIdent ("D_BetterC");
|
|
else
|
|
{
|
|
VersionCondition::addPredefinedGlobalIdent ("D_ModuleInfo");
|
|
VersionCondition::addPredefinedGlobalIdent ("D_Exceptions");
|
|
VersionCondition::addPredefinedGlobalIdent ("D_TypeInfo");
|
|
}
|
|
|
|
VersionCondition::addPredefinedGlobalIdent ("all");
|
|
|
|
/* Emit all target-specific version identifiers. */
|
|
targetdm.d_cpu_versions ();
|
|
targetdm.d_os_versions ();
|
|
|
|
VersionCondition::addPredefinedGlobalIdent ("CppRuntime_Gcc");
|
|
}
|
|
|
|
/* A helper for d_build_builtins_module. Return a new ALIAS for TYPE.
|
|
Analogous to `alias ALIAS = TYPE' in D code. */
|
|
|
|
static AliasDeclaration *
|
|
build_alias_declaration (const char *alias, Type *type)
|
|
{
|
|
return AliasDeclaration::create (Loc (), Identifier::idPool (alias), type);
|
|
}
|
|
|
|
/* A helper function for Target::loadModule. Generates all code for the
|
|
`gcc.builtins' module, whose frontend symbol should be M. */
|
|
|
|
void
|
|
d_build_builtins_module (Module *m)
|
|
{
|
|
Dsymbols *members = new Dsymbols;
|
|
tree decl;
|
|
|
|
for (size_t i = 0; vec_safe_iterate (gcc_builtins_functions, i, &decl); ++i)
|
|
{
|
|
const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
|
|
Type *t = build_frontend_type (TREE_TYPE (decl));
|
|
TypeFunction *tf = t ? t->isTypeFunction () : NULL;
|
|
|
|
/* Cannot create built-in function type for DECL. */
|
|
if (!tf)
|
|
continue;
|
|
|
|
/* A few notes on D2 attributes applied to builtin functions:
|
|
- It is assumed that built-ins solely provided by the compiler are
|
|
considered @safe and pure.
|
|
- Built-ins that correspond to `extern(C)' functions in the standard
|
|
library that have `__attribute__(nothrow)' are considered `@trusted'.
|
|
- The purity of a built-in can vary depending on compiler flags set
|
|
upon initialization, or by the `-foptions' passed, such as
|
|
flag_unsafe_math_optimizations.
|
|
- Built-ins never use the GC or raise a D exception, and so are always
|
|
marked as `nothrow' and `@nogc'. */
|
|
tf->purity = DECL_PURE_P (decl) ? PUREstrong
|
|
: TREE_READONLY (decl) ? PUREconst
|
|
: DECL_IS_NOVOPS (decl) ? PUREweak
|
|
: !DECL_ASSEMBLER_NAME_SET_P (decl) ? PUREweak
|
|
: PUREimpure;
|
|
tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUSTsafe
|
|
: TREE_NOTHROW (decl) ? TRUSTtrusted
|
|
: TRUSTsystem;
|
|
tf->isnothrow = true;
|
|
tf->isnogc = true;
|
|
|
|
FuncDeclaration *func
|
|
= FuncDeclaration::create (Loc (), Loc (),
|
|
Identifier::idPool (name),
|
|
STCextern, tf);
|
|
DECL_LANG_SPECIFIC (decl) = build_lang_decl (func);
|
|
func->csym = decl;
|
|
func->builtin = BUILTINgcc;
|
|
|
|
members->push (func);
|
|
}
|
|
|
|
for (size_t i = 0; vec_safe_iterate (gcc_builtins_types, i, &decl); ++i)
|
|
{
|
|
const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
|
|
Type *t = build_frontend_type (TREE_TYPE (decl));
|
|
|
|
/* Cannot create built-in type for DECL. */
|
|
if (!t)
|
|
continue;
|
|
|
|
members->push (build_alias_declaration (name, t));
|
|
}
|
|
|
|
/* Iterate through the target-specific builtin types for va_list. */
|
|
if (targetm.enum_va_list_p)
|
|
{
|
|
const char *name;
|
|
tree type;
|
|
|
|
for (int i = 0; targetm.enum_va_list_p (i, &name, &type); ++i)
|
|
{
|
|
Type *t = build_frontend_type (type);
|
|
/* Cannot create built-in type. */
|
|
if (!t)
|
|
continue;
|
|
|
|
members->push (build_alias_declaration (name, t));
|
|
}
|
|
}
|
|
|
|
/* Push out declarations for any RECORD_TYPE types encountered when building
|
|
all builtin functions and types. */
|
|
for (size_t i = 0; i < builtin_converted_decls.length (); ++i)
|
|
{
|
|
/* Currently, there is no need to run semantic, but we do want to output
|
|
initializers, typeinfo, and others on demand. */
|
|
Dsymbol *dsym = builtin_converted_decls[i].dsym;
|
|
if (dsym != NULL && !dsym->isAnonymous ())
|
|
{
|
|
dsym->parent = m;
|
|
members->push (dsym);
|
|
}
|
|
}
|
|
|
|
/* Expose target-specific va_list type. */
|
|
Type *tvalist = target.va_listType (Loc (), NULL);
|
|
TypeStruct *ts = tvalist->isTypeStruct ();
|
|
if (ts == NULL || !ts->sym->isAnonymous ())
|
|
members->push (build_alias_declaration ("__builtin_va_list", tvalist));
|
|
else
|
|
{
|
|
ts->sym->ident = Identifier::idPool ("__builtin_va_list");
|
|
members->push (ts->sym);
|
|
}
|
|
|
|
/* Expose target-specific integer types to the builtins module. */
|
|
{
|
|
Type *t = build_frontend_type (long_integer_type_node);
|
|
members->push (build_alias_declaration ("__builtin_clong", t));
|
|
|
|
t = build_frontend_type (long_unsigned_type_node);
|
|
members->push (build_alias_declaration ("__builtin_culong", t));
|
|
|
|
t = build_frontend_type (long_long_integer_type_node);
|
|
members->push (build_alias_declaration ("__builtin_clonglong", t));
|
|
|
|
t = build_frontend_type (long_long_unsigned_type_node);
|
|
members->push (build_alias_declaration ("__builtin_culonglong", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 0));
|
|
members->push (build_alias_declaration ("__builtin_machine_byte", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 1));
|
|
members->push (build_alias_declaration ("__builtin_machine_ubyte", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 0));
|
|
members->push (build_alias_declaration ("__builtin_machine_int", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 1));
|
|
members->push (build_alias_declaration ("__builtin_machine_uint", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 0));
|
|
members->push (build_alias_declaration ("__builtin_pointer_int", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 1));
|
|
members->push (build_alias_declaration ("__builtin_pointer_uint", t));
|
|
|
|
/* _Unwind_Word has its own target specific mode. */
|
|
machine_mode mode = targetm.unwind_word_mode ();
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 0));
|
|
members->push (build_alias_declaration ("__builtin_unwind_int", t));
|
|
|
|
t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 1));
|
|
members->push (build_alias_declaration ("__builtin_unwind_uint", t));
|
|
}
|
|
|
|
m->members->push (LinkDeclaration::create (LINKc, members));
|
|
}
|
|
|
|
/* Search for any `extern(C)' functions that match any known GCC library builtin
|
|
function in D and override its internal back-end symbol. */
|
|
|
|
static void
|
|
maybe_set_builtin_1 (Dsymbol *d)
|
|
{
|
|
AttribDeclaration *ad = d->isAttribDeclaration ();
|
|
FuncDeclaration *fd = d->isFuncDeclaration ();
|
|
|
|
if (ad != NULL)
|
|
{
|
|
/* Recursively search through attribute decls. */
|
|
Dsymbols *decls = ad->include (NULL);
|
|
if (decls && decls->length)
|
|
{
|
|
for (size_t i = 0; i < decls->length; i++)
|
|
{
|
|
Dsymbol *sym = (*decls)[i];
|
|
maybe_set_builtin_1 (sym);
|
|
}
|
|
}
|
|
}
|
|
else if (fd && !fd->fbody)
|
|
{
|
|
tree t;
|
|
|
|
for (size_t i = 0; vec_safe_iterate (gcc_builtins_libfuncs, i, &t); ++i)
|
|
{
|
|
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (t));
|
|
|
|
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t));
|
|
if (fd->ident != Identifier::idPool (name))
|
|
continue;
|
|
|
|
/* Found a match, tell the frontend this is a builtin. */
|
|
DECL_LANG_SPECIFIC (t) = build_lang_decl (fd);
|
|
fd->csym = t;
|
|
fd->builtin = BUILTINgcc;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* A helper function for Target::loadModule. Traverse all members in module M
|
|
to search for any functions that can be mapped to any GCC builtin. */
|
|
|
|
void
|
|
d_maybe_set_builtin (Module *m)
|
|
{
|
|
if (!m || !m->members)
|
|
return;
|
|
|
|
for (size_t i = 0; i < m->members->length; i++)
|
|
{
|
|
Dsymbol *sym = (*m->members)[i];
|
|
maybe_set_builtin_1 (sym);
|
|
}
|
|
}
|
|
|
|
/* Used to help initialize the builtin-types.def table. When a type of
|
|
the correct size doesn't exist, use error_mark_node instead of NULL.
|
|
The latter results in segfaults even when a decl using the type doesn't
|
|
get invoked. */
|
|
|
|
static tree
|
|
builtin_type_for_size (int size, bool unsignedp)
|
|
{
|
|
tree type = lang_hooks.types.type_for_size (size, unsignedp);
|
|
return type ? type : error_mark_node;
|
|
}
|
|
|
|
/* Support for DEF_BUILTIN. */
|
|
|
|
static void
|
|
do_build_builtin_fn (built_in_function fncode,
|
|
const char *name,
|
|
built_in_class fnclass,
|
|
tree fntype, bool both_p, bool fallback_p,
|
|
tree fnattrs, bool implicit_p)
|
|
{
|
|
tree decl;
|
|
const char *libname;
|
|
|
|
if (fntype == error_mark_node)
|
|
return;
|
|
|
|
gcc_assert ((!both_p && !fallback_p)
|
|
|| !strncmp (name, "__builtin_",
|
|
strlen ("__builtin_")));
|
|
|
|
libname = name + strlen ("__builtin_");
|
|
|
|
decl = add_builtin_function (name, fntype, fncode, fnclass,
|
|
fallback_p ? libname : NULL, fnattrs);
|
|
|
|
set_builtin_decl (fncode, decl, implicit_p);
|
|
}
|
|
|
|
/* Standard data types to be used in builtin argument declarations. */
|
|
|
|
static GTY(()) tree string_type_node;
|
|
static GTY(()) tree const_string_type_node;
|
|
static GTY(()) tree wint_type_node;
|
|
static GTY(()) tree intmax_type_node;
|
|
static GTY(()) tree uintmax_type_node;
|
|
static GTY(()) tree signed_size_type_node;
|
|
|
|
|
|
/* Build nodes that would have been created by the C front-end; necessary
|
|
for including builtin-types.def and ultimately builtins.def. */
|
|
|
|
static void
|
|
d_build_c_type_nodes (void)
|
|
{
|
|
void_list_node = build_tree_list (NULL_TREE, void_type_node);
|
|
string_type_node = build_pointer_type (char_type_node);
|
|
const_string_type_node
|
|
= build_pointer_type (build_qualified_type (char_type_node,
|
|
TYPE_QUAL_CONST));
|
|
|
|
if (strcmp (UINTMAX_TYPE, "unsigned int") == 0)
|
|
{
|
|
intmax_type_node = integer_type_node;
|
|
uintmax_type_node = unsigned_type_node;
|
|
}
|
|
else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0)
|
|
{
|
|
intmax_type_node = long_integer_type_node;
|
|
uintmax_type_node = long_unsigned_type_node;
|
|
}
|
|
else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0)
|
|
{
|
|
intmax_type_node = long_long_integer_type_node;
|
|
uintmax_type_node = long_long_unsigned_type_node;
|
|
}
|
|
else
|
|
gcc_unreachable ();
|
|
|
|
signed_size_type_node = signed_type_for (size_type_node);
|
|
wint_type_node = unsigned_type_node;
|
|
pid_type_node = integer_type_node;
|
|
}
|
|
|
|
/* Build nodes that are used by the D front-end.
|
|
These are distinct from C types. */
|
|
|
|
static void
|
|
d_build_d_type_nodes (void)
|
|
{
|
|
/* Integral types. */
|
|
d_byte_type = make_signed_type (8);
|
|
d_ubyte_type = make_unsigned_type (8);
|
|
|
|
d_short_type = make_signed_type (16);
|
|
d_ushort_type = make_unsigned_type (16);
|
|
|
|
d_int_type = make_signed_type (32);
|
|
d_uint_type = make_unsigned_type (32);
|
|
|
|
d_long_type = make_signed_type (64);
|
|
d_ulong_type = make_unsigned_type (64);
|
|
|
|
d_cent_type = make_signed_type (128);
|
|
d_ucent_type = make_unsigned_type (128);
|
|
|
|
{
|
|
/* Re-define size_t as a D type. */
|
|
machine_mode type_mode = TYPE_MODE (size_type_node);
|
|
size_type_node = lang_hooks.types.type_for_mode (type_mode, 1);
|
|
}
|
|
|
|
/* Bool and Character types. */
|
|
d_bool_type = make_unsigned_type (1);
|
|
TREE_SET_CODE (d_bool_type, BOOLEAN_TYPE);
|
|
|
|
char8_type_node = make_unsigned_type (8);
|
|
TYPE_STRING_FLAG (char8_type_node) = 1;
|
|
|
|
char16_type_node = make_unsigned_type (16);
|
|
TYPE_STRING_FLAG (char16_type_node) = 1;
|
|
|
|
char32_type_node = make_unsigned_type (32);
|
|
TYPE_STRING_FLAG (char32_type_node) = 1;
|
|
|
|
/* Imaginary types. */
|
|
ifloat_type_node = build_distinct_type_copy (float_type_node);
|
|
TYPE_IMAGINARY_FLOAT (ifloat_type_node) = 1;
|
|
|
|
idouble_type_node = build_distinct_type_copy (double_type_node);
|
|
TYPE_IMAGINARY_FLOAT (idouble_type_node) = 1;
|
|
|
|
ireal_type_node = build_distinct_type_copy (long_double_type_node);
|
|
TYPE_IMAGINARY_FLOAT (ireal_type_node) = 1;
|
|
|
|
/* Calling build_ctype() links the front-end Type to the GCC node,
|
|
and sets the TYPE_NAME to the D language type. */
|
|
for (unsigned ty = 0; ty < TMAX; ty++)
|
|
{
|
|
if (Type::basic[ty] != NULL)
|
|
build_ctype (Type::basic[ty]);
|
|
}
|
|
|
|
/* Used for ModuleInfo, ClassInfo, and Interface decls. */
|
|
unknown_type_node = make_node (RECORD_TYPE);
|
|
|
|
/* Make sure we get a unique function type, so we can give
|
|
its pointer type a name. (This wins for gdb). */
|
|
{
|
|
tree vfunc_type = make_node (FUNCTION_TYPE);
|
|
TREE_TYPE (vfunc_type) = d_int_type;
|
|
TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
|
|
layout_type (vfunc_type);
|
|
|
|
vtable_entry_type = build_pointer_type (vfunc_type);
|
|
}
|
|
|
|
vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
|
|
layout_type (vtbl_ptr_type_node);
|
|
|
|
/* When an object is accessed via an interface, this type appears
|
|
as the first entry in its vtable. */
|
|
{
|
|
tree domain = build_index_type (size_int (3));
|
|
vtbl_interface_type_node = build_array_type (ptr_type_node, domain);
|
|
}
|
|
|
|
/* Use `void[]' as a generic dynamic array type. */
|
|
array_type_node = make_struct_type ("__builtin_void[]", 2,
|
|
get_identifier ("length"), size_type_node,
|
|
get_identifier ("ptr"), ptr_type_node);
|
|
TYPE_DYNAMIC_ARRAY (array_type_node) = 1;
|
|
|
|
null_array_node = d_array_value (array_type_node, size_zero_node,
|
|
null_pointer_node);
|
|
}
|
|
|
|
/* Handle default attributes. */
|
|
|
|
enum built_in_attribute
|
|
{
|
|
#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
|
|
#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
|
|
#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
|
|
#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
|
|
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
|
|
#include "builtin-attrs.def"
|
|
#undef DEF_ATTR_NULL_TREE
|
|
#undef DEF_ATTR_INT
|
|
#undef DEF_ATTR_STRING
|
|
#undef DEF_ATTR_IDENT
|
|
#undef DEF_ATTR_TREE_LIST
|
|
ATTR_LAST
|
|
};
|
|
|
|
static GTY(()) tree built_in_attributes[(int) ATTR_LAST];
|
|
|
|
/* Initialize the attribute table for all the supported builtins. */
|
|
|
|
static void
|
|
d_init_attributes (void)
|
|
{
|
|
/* Fill in the built_in_attributes array. */
|
|
#define DEF_ATTR_NULL_TREE(ENUM) \
|
|
built_in_attributes[(int) ENUM] = NULL_TREE;
|
|
# define DEF_ATTR_INT(ENUM, VALUE) \
|
|
built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
|
|
#define DEF_ATTR_STRING(ENUM, VALUE) \
|
|
built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
|
|
#define DEF_ATTR_IDENT(ENUM, STRING) \
|
|
built_in_attributes[(int) ENUM] = get_identifier (STRING);
|
|
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
|
|
built_in_attributes[(int) ENUM] \
|
|
= tree_cons (built_in_attributes[(int) PURPOSE], \
|
|
built_in_attributes[(int) VALUE], \
|
|
built_in_attributes[(int) CHAIN]);
|
|
#include "builtin-attrs.def"
|
|
#undef DEF_ATTR_NULL_TREE
|
|
#undef DEF_ATTR_INT
|
|
#undef DEF_ATTR_STRING
|
|
#undef DEF_ATTR_IDENT
|
|
#undef DEF_ATTR_TREE_LIST
|
|
}
|
|
|
|
/* Builtin types. */
|
|
|
|
enum d_builtin_type
|
|
{
|
|
#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
|
|
#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
|
|
#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
|
|
#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
|
|
#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
|
|
#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
|
|
#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
|
|
#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6) NAME,
|
|
#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7) NAME,
|
|
#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8) NAME,
|
|
#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9) NAME,
|
|
#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9, ARG10) NAME,
|
|
#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
|
NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7) NAME,
|
|
#define DEF_FUNCTION_TYPE_VAR_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
|
|
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
|
|
#include "builtin-types.def"
|
|
#undef DEF_PRIMITIVE_TYPE
|
|
#undef DEF_FUNCTION_TYPE_0
|
|
#undef DEF_FUNCTION_TYPE_1
|
|
#undef DEF_FUNCTION_TYPE_2
|
|
#undef DEF_FUNCTION_TYPE_3
|
|
#undef DEF_FUNCTION_TYPE_4
|
|
#undef DEF_FUNCTION_TYPE_5
|
|
#undef DEF_FUNCTION_TYPE_6
|
|
#undef DEF_FUNCTION_TYPE_7
|
|
#undef DEF_FUNCTION_TYPE_8
|
|
#undef DEF_FUNCTION_TYPE_9
|
|
#undef DEF_FUNCTION_TYPE_10
|
|
#undef DEF_FUNCTION_TYPE_11
|
|
#undef DEF_FUNCTION_TYPE_VAR_0
|
|
#undef DEF_FUNCTION_TYPE_VAR_1
|
|
#undef DEF_FUNCTION_TYPE_VAR_2
|
|
#undef DEF_FUNCTION_TYPE_VAR_3
|
|
#undef DEF_FUNCTION_TYPE_VAR_4
|
|
#undef DEF_FUNCTION_TYPE_VAR_5
|
|
#undef DEF_FUNCTION_TYPE_VAR_6
|
|
#undef DEF_FUNCTION_TYPE_VAR_7
|
|
#undef DEF_FUNCTION_TYPE_VAR_11
|
|
#undef DEF_POINTER_TYPE
|
|
BT_LAST
|
|
};
|
|
|
|
typedef enum d_builtin_type builtin_type;
|
|
|
|
/* A temporary array used in communication with def_fn_type. */
|
|
static GTY(()) tree builtin_types[(int) BT_LAST + 1];
|
|
|
|
/* A helper function for d_init_builtins. Build function type for DEF with
|
|
return type RET and N arguments. If VAR is true, then the function should
|
|
be variadic after those N arguments.
|
|
|
|
Takes special care not to ICE if any of the types involved are
|
|
error_mark_node, which indicates that said type is not in fact available
|
|
(see builtin_type_for_size). In which case the function type as a whole
|
|
should be error_mark_node. */
|
|
|
|
static void
|
|
def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
|
|
{
|
|
tree t;
|
|
tree *args = XALLOCAVEC (tree, n);
|
|
va_list list;
|
|
int i;
|
|
|
|
va_start (list, n);
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
builtin_type a = (builtin_type) va_arg (list, int);
|
|
t = builtin_types[a];
|
|
if (t == error_mark_node)
|
|
goto egress;
|
|
args[i] = t;
|
|
}
|
|
|
|
t = builtin_types[ret];
|
|
if (t == error_mark_node)
|
|
goto egress;
|
|
if (var)
|
|
t = build_varargs_function_type_array (t, n, args);
|
|
else
|
|
t = build_function_type_array (t, n, args);
|
|
|
|
egress:
|
|
builtin_types[def] = t;
|
|
va_end (list);
|
|
}
|
|
|
|
/* Create builtin types and functions. VA_LIST_REF_TYPE_NODE and
|
|
VA_LIST_ARG_TYPE_NODE are used in builtin-types.def. */
|
|
|
|
static void
|
|
d_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
|
|
tree va_list_arg_type_node ATTRIBUTE_UNUSED)
|
|
{
|
|
#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
|
|
builtin_types[(int) ENUM] = VALUE;
|
|
#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
|
|
def_fn_type (ENUM, RETURN, 0, 0);
|
|
#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
|
|
def_fn_type (ENUM, RETURN, 0, 1, ARG1);
|
|
#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
|
|
def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
|
|
#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
|
|
def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
|
|
#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
|
|
def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
|
|
#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
|
def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
|
|
#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6) \
|
|
def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7) \
|
|
def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
|
|
#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8) \
|
|
def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
|
|
ARG7, ARG8);
|
|
#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9) \
|
|
def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
|
|
ARG7, ARG8, ARG9);
|
|
#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9, ARG10) \
|
|
def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
|
|
ARG7, ARG8, ARG9, ARG10);
|
|
#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \
|
|
def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
|
|
ARG7, ARG8, ARG9, ARG10, ARG11);
|
|
#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
|
|
def_fn_type (ENUM, RETURN, 1, 0);
|
|
#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
|
|
def_fn_type (ENUM, RETURN, 1, 1, ARG1);
|
|
#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
|
|
def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
|
|
#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
|
|
def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
|
|
#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
|
|
def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
|
|
#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
|
def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
|
|
#define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6) \
|
|
def_fn_type (ENUM, RETURN, 1, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7) \
|
|
def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
|
|
#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
|
ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \
|
|
def_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
|
|
ARG7, ARG8, ARG9, ARG10, ARG11);
|
|
#define DEF_POINTER_TYPE(ENUM, TYPE) \
|
|
builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
|
|
|
|
#include "builtin-types.def"
|
|
|
|
#undef DEF_PRIMITIVE_TYPE
|
|
#undef DEF_FUNCTION_TYPE_1
|
|
#undef DEF_FUNCTION_TYPE_2
|
|
#undef DEF_FUNCTION_TYPE_3
|
|
#undef DEF_FUNCTION_TYPE_4
|
|
#undef DEF_FUNCTION_TYPE_5
|
|
#undef DEF_FUNCTION_TYPE_6
|
|
#undef DEF_FUNCTION_TYPE_7
|
|
#undef DEF_FUNCTION_TYPE_8
|
|
#undef DEF_FUNCTION_TYPE_9
|
|
#undef DEF_FUNCTION_TYPE_10
|
|
#undef DEF_FUNCTION_TYPE_11
|
|
#undef DEF_FUNCTION_TYPE_VAR_0
|
|
#undef DEF_FUNCTION_TYPE_VAR_1
|
|
#undef DEF_FUNCTION_TYPE_VAR_2
|
|
#undef DEF_FUNCTION_TYPE_VAR_3
|
|
#undef DEF_FUNCTION_TYPE_VAR_4
|
|
#undef DEF_FUNCTION_TYPE_VAR_5
|
|
#undef DEF_FUNCTION_TYPE_VAR_6
|
|
#undef DEF_FUNCTION_TYPE_VAR_7
|
|
#undef DEF_FUNCTION_TYPE_VAR_11
|
|
#undef DEF_POINTER_TYPE
|
|
builtin_types[(int) BT_LAST] = NULL_TREE;
|
|
|
|
d_init_attributes ();
|
|
|
|
#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
|
|
NONANSI_P, ATTRS, IMPLICIT, COND) \
|
|
if (NAME && COND) \
|
|
do_build_builtin_fn (ENUM, NAME, CLASS, \
|
|
builtin_types[(int) TYPE], \
|
|
BOTH_P, FALLBACK_P, \
|
|
built_in_attributes[(int) ATTRS], IMPLICIT);
|
|
#include "builtins.def"
|
|
#undef DEF_BUILTIN
|
|
}
|
|
|
|
/* Build builtin functions and types for the D language frontend. */
|
|
|
|
void
|
|
d_init_builtins (void)
|
|
{
|
|
d_build_c_type_nodes ();
|
|
d_build_d_type_nodes ();
|
|
|
|
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
|
|
{
|
|
/* It might seem natural to make the argument type a pointer, but there
|
|
is no implicit casting from arrays to pointers in D. */
|
|
d_define_builtins (va_list_type_node, va_list_type_node);
|
|
}
|
|
else
|
|
{
|
|
d_define_builtins (build_reference_type (va_list_type_node),
|
|
va_list_type_node);
|
|
}
|
|
|
|
targetm.init_builtins ();
|
|
build_common_builtin_nodes ();
|
|
}
|
|
|
|
/* Registration of machine- or os-specific builtin types.
|
|
Add to builtin types list for maybe processing later
|
|
if `gcc.builtins' was imported into the current module. */
|
|
|
|
void
|
|
d_register_builtin_type (tree type, const char *name)
|
|
{
|
|
tree decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL,
|
|
get_identifier (name), type);
|
|
DECL_ARTIFICIAL (decl) = 1;
|
|
|
|
if (!TYPE_NAME (type))
|
|
TYPE_NAME (type) = decl;
|
|
|
|
vec_safe_push (gcc_builtins_types, decl);
|
|
}
|
|
|
|
/* Add DECL to builtin functions list for maybe processing later
|
|
if `gcc.builtins' was imported into the current module. */
|
|
|
|
tree
|
|
d_builtin_function (tree decl)
|
|
{
|
|
if (!flag_no_builtin && DECL_ASSEMBLER_NAME_SET_P (decl))
|
|
vec_safe_push (gcc_builtins_libfuncs, decl);
|
|
|
|
vec_safe_push (gcc_builtins_functions, decl);
|
|
return decl;
|
|
}
|
|
|
|
/* Same as d_builtin_function, but used to delay putting in back-end builtin
|
|
functions until the ISA that defines the builtin has been declared.
|
|
However in D, there is no global namespace. All builtins get pushed into the
|
|
`gcc.builtins' module, which is constructed during the semantic analysis
|
|
pass, which has already finished by the time target attributes are evaluated.
|
|
So builtins are not pushed because they would be ultimately ignored.
|
|
The purpose of having this function then is to improve compile-time
|
|
reflection support to allow user-code to determine whether a given back end
|
|
function is enabled by the ISA. */
|
|
|
|
tree
|
|
d_builtin_function_ext_scope (tree decl)
|
|
{
|
|
return decl;
|
|
}
|
|
|
|
#include "gt-d-d-builtins.h"
|