d: Split up d-frontend.cc into multiple parts.
gcc/d/ChangeLog: * Make-lang.in (D_OBJS): Add d-compiler.o, d-ctfloat.o, d-port.o. * d-frontend.cc (Port::memicmp): Move to d-port.cc. (Port::strupr): Likewise. (Port::isFloat32LiteralOutOfRange): Likewise. (Port::isFloat64LiteralOutOfRange): Likewise. (Port::readwordLE): Likewise. (Port::readwordBE): Likewise. (Port::readlongLE): Likewise. (Port::readlongBE): Likewise. (Port::valcpy): Likewise. (CTFloat::fabs): Move to d-ctfloat.cc. (CTFloat::ldexp): Likewise. (CTFloat::isIdentical): Likewise. (CTFloat::isNaN): Likewise. (CTFloat::isSNaN): Likewise. (CTFloat::isInfinity): Likewise. (CTFloat::parse): Likewise. (CTFloat::sprint): Likewise. (CTFloat::hash): Likewise. (Compiler::genCmain): Move to d-compiler.cc. (Compiler::paintAsType): Likewise. (Compiler::loadModule): Likewise. * d-compiler.cc: New file. * d-ctfloat.cc: New file. * d-port.cc: New file.
This commit is contained in:
parent
5261cf8ce8
commit
2803d2f27c
5 changed files with 516 additions and 420 deletions
|
@ -133,10 +133,28 @@ D_GENERATED_OBJS = d/id.o d/impcnvtab.o
|
|||
|
||||
# Language-specific object files for D.
|
||||
D_OBJS = \
|
||||
d/d-attribs.o d/d-builtins.o d/d-codegen.o d/d-convert.o \
|
||||
d/d-diagnostic.o d/d-frontend.o d/d-incpath.o d/d-lang.o \
|
||||
d/d-longdouble.o d/d-target.o d/decl.o d/expr.o d/imports.o \
|
||||
d/intrinsics.o d/modules.o d/runtime.o d/toir.o d/typeinfo.o d/types.o
|
||||
d/d-attribs.o \
|
||||
d/d-builtins.o \
|
||||
d/d-codegen.o \
|
||||
d/d-compiler.o \
|
||||
d/d-convert.o \
|
||||
d/d-ctfloat.o \
|
||||
d/d-diagnostic.o \
|
||||
d/d-frontend.o \
|
||||
d/d-incpath.o \
|
||||
d/d-lang.o \
|
||||
d/d-longdouble.o \
|
||||
d/d-port.o \
|
||||
d/d-target.o \
|
||||
d/decl.o \
|
||||
d/expr.o \
|
||||
d/imports.o \
|
||||
d/intrinsics.o \
|
||||
d/modules.o \
|
||||
d/runtime.o \
|
||||
d/toir.o \
|
||||
d/typeinfo.o \
|
||||
d/types.o
|
||||
|
||||
# All language-specific object files for D.
|
||||
D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_GENERATED_OBJS) $(D_OBJS) $(D_TARGET_OBJS)
|
||||
|
|
182
gcc/d/d-compiler.cc
Normal file
182
gcc/d/d-compiler.cc
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* d-compiler.cc -- D frontend interface to the gcc back-end.
|
||||
Copyright (C) 2020 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/compiler.h"
|
||||
#include "dmd/scope.h"
|
||||
#include "dmd/expression.h"
|
||||
#include "dmd/identifier.h"
|
||||
#include "dmd/module.h"
|
||||
#include "dmd/mtype.h"
|
||||
|
||||
#include "tree.h"
|
||||
#include "fold-const.h"
|
||||
|
||||
#include "d-tree.h"
|
||||
|
||||
|
||||
/* Implements the Compiler interface used by the frontend. */
|
||||
|
||||
/* Generate C main() in response to seeing D main(). This used to be in
|
||||
libdruntime, but contained a reference to _Dmain which didn't work when
|
||||
druntime was made into a shared library and was linked to a program, such
|
||||
as a C++ program, that didn't have a _Dmain. */
|
||||
|
||||
void
|
||||
Compiler::genCmain (Scope *sc)
|
||||
{
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
/* The D code to be generated is provided by __entrypoint.di, try to load it,
|
||||
but don't fail if unfound. */
|
||||
unsigned errors = global.startGagging ();
|
||||
Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint"));
|
||||
|
||||
if (global.endGagging (errors))
|
||||
m = NULL;
|
||||
|
||||
if (m != NULL)
|
||||
{
|
||||
m->importedFrom = m;
|
||||
m->importAll (NULL);
|
||||
m->semantic (NULL);
|
||||
m->semantic2 (NULL);
|
||||
m->semantic3 (NULL);
|
||||
d_add_entrypoint_module (m, sc->_module);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
|
||||
The front end should have already ensured that EXPR is a constant,
|
||||
so we just lower the value to GCC and return the converted CST. */
|
||||
|
||||
Expression *
|
||||
Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
|
||||
{
|
||||
/* We support up to 512-bit values. */
|
||||
unsigned char buffer[64];
|
||||
tree cst;
|
||||
|
||||
Type *tb = type->toBasetype ();
|
||||
|
||||
if (expr->type->isintegral ())
|
||||
cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
|
||||
else if (expr->type->isfloating ())
|
||||
cst = build_float_cst (expr->toReal (), expr->type);
|
||||
else if (expr->op == TOKarrayliteral)
|
||||
{
|
||||
/* Build array as VECTOR_CST, assumes EXPR is constant. */
|
||||
Expressions *elements = ((ArrayLiteralExp *) expr)->elements;
|
||||
vec<constructor_elt, va_gc> *elms = NULL;
|
||||
|
||||
vec_safe_reserve (elms, elements->dim);
|
||||
for (size_t i = 0; i < elements->dim; i++)
|
||||
{
|
||||
Expression *e = (*elements)[i];
|
||||
if (e->type->isintegral ())
|
||||
{
|
||||
tree value = build_integer_cst (e->toInteger (),
|
||||
build_ctype (e->type));
|
||||
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
|
||||
}
|
||||
else if (e->type->isfloating ())
|
||||
{
|
||||
tree value = build_float_cst (e->toReal (), e->type);
|
||||
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Build vector type. */
|
||||
int nunits = ((TypeSArray *) expr->type)->dim->toUInteger ();
|
||||
Type *telem = expr->type->nextOf ();
|
||||
tree vectype = build_vector_type (build_ctype (telem), nunits);
|
||||
|
||||
cst = build_vector_from_ctor (vectype, elms);
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
/* Encode CST to buffer. */
|
||||
int len = native_encode_expr (cst, buffer, sizeof (buffer));
|
||||
|
||||
if (tb->ty == Tsarray)
|
||||
{
|
||||
/* Interpret value as a vector of the same size,
|
||||
then return the array literal. */
|
||||
int nunits = ((TypeSArray *) type)->dim->toUInteger ();
|
||||
Type *elem = type->nextOf ();
|
||||
tree vectype = build_vector_type (build_ctype (elem), nunits);
|
||||
|
||||
cst = native_interpret_expr (vectype, buffer, len);
|
||||
|
||||
Expression *e = d_eval_constant_expression (cst);
|
||||
gcc_assert (e != NULL && e->op == TOKvector);
|
||||
|
||||
return ((VectorExp *) e)->e1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal interpret cast. */
|
||||
cst = native_interpret_expr (build_ctype (type), buffer, len);
|
||||
|
||||
Expression *e = d_eval_constant_expression (cst);
|
||||
gcc_assert (e != NULL);
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check imported module M for any special processing.
|
||||
Modules we look out for are:
|
||||
- object: For D runtime type information.
|
||||
- gcc.builtins: For all gcc builtins.
|
||||
- core.stdc.*: For all gcc library builtins. */
|
||||
|
||||
void
|
||||
Compiler::loadModule (Module *m)
|
||||
{
|
||||
ModuleDeclaration *md = m->md;
|
||||
|
||||
if (!md || !md->id || !md->packages)
|
||||
{
|
||||
Identifier *id = (md && md->id) ? md->id : m->ident;
|
||||
if (!strcmp (id->toChars (), "object"))
|
||||
create_tinfo_types (m);
|
||||
}
|
||||
else if (md->packages->dim == 1)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
|
||||
&& !strcmp (md->id->toChars (), "builtins"))
|
||||
d_build_builtins_module (m);
|
||||
}
|
||||
else if (md->packages->dim == 2)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "core")
|
||||
&& !strcmp ((*md->packages)[1]->toChars (), "stdc"))
|
||||
d_add_builtin_module (m);
|
||||
}
|
||||
}
|
143
gcc/d/d-ctfloat.cc
Normal file
143
gcc/d/d-ctfloat.cc
Normal file
|
@ -0,0 +1,143 @@
|
|||
/* d-ctfloat.cc -- D frontend interface to the gcc back-end.
|
||||
Copyright (C) 2020 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/root/ctfloat.h"
|
||||
#include "dmd/target.h"
|
||||
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
/* Implements the CTFloat interface defined by the frontend.
|
||||
Compile-time floating-pointer helper functions. */
|
||||
|
||||
/* Return the absolute value of R. */
|
||||
|
||||
real_t
|
||||
CTFloat::fabs (real_t r)
|
||||
{
|
||||
real_t x;
|
||||
real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL);
|
||||
return x.normalize ();
|
||||
}
|
||||
|
||||
/* Return the value of R * 2 ^^ EXP. */
|
||||
|
||||
real_t
|
||||
CTFloat::ldexp (real_t r, int exp)
|
||||
{
|
||||
real_t x;
|
||||
real_ldexp (&x.rv (), &r.rv (), exp);
|
||||
return x.normalize ();
|
||||
}
|
||||
|
||||
/* Return true if longdouble value X is identical to Y. */
|
||||
|
||||
bool
|
||||
CTFloat::isIdentical (real_t x, real_t y)
|
||||
{
|
||||
real_value rx = x.rv ();
|
||||
real_value ry = y.rv ();
|
||||
return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
|
||||
|| real_identical (&rx, &ry);
|
||||
}
|
||||
|
||||
/* Return true if real_t value R is NaN. */
|
||||
|
||||
bool
|
||||
CTFloat::isNaN (real_t r)
|
||||
{
|
||||
return REAL_VALUE_ISNAN (r.rv ());
|
||||
}
|
||||
|
||||
/* Same as isNaN, but also check if is signalling. */
|
||||
|
||||
bool
|
||||
CTFloat::isSNaN (real_t r)
|
||||
{
|
||||
return REAL_VALUE_ISSIGNALING_NAN (r.rv ());
|
||||
}
|
||||
|
||||
/* Return true if real_t value is +Inf. */
|
||||
|
||||
bool
|
||||
CTFloat::isInfinity (real_t r)
|
||||
{
|
||||
return REAL_VALUE_ISINF (r.rv ());
|
||||
}
|
||||
|
||||
/* Return a real_t value from string BUFFER rounded to long double mode. */
|
||||
|
||||
real_t
|
||||
CTFloat::parse (const char *buffer, bool *overflow)
|
||||
{
|
||||
real_t r;
|
||||
real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
|
||||
|
||||
/* Front-end checks overflow to see if the value is representable. */
|
||||
if (overflow && r == Target::RealProperties::infinity)
|
||||
*overflow = true;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
|
||||
converting the result to uppercase if FMT requests it. */
|
||||
|
||||
int
|
||||
CTFloat::sprint (char *buffer, char fmt, real_t r)
|
||||
{
|
||||
if (fmt == 'a' || fmt == 'A')
|
||||
{
|
||||
/* Converting to a hexadecimal string. */
|
||||
real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
|
||||
int buflen;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case 'A':
|
||||
buflen = strlen (buffer);
|
||||
for (int i = 0; i < buflen; i++)
|
||||
buffer[i] = TOUPPER (buffer[i]);
|
||||
|
||||
return buflen;
|
||||
|
||||
case 'a':
|
||||
return strlen (buffer);
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note: restricting the precision of significant digits to 18. */
|
||||
real_to_decimal (buffer, &r.rv (), 32, 18, 1);
|
||||
return strlen (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a hash value for real_t value R. */
|
||||
|
||||
size_t
|
||||
CTFloat::hash (real_t r)
|
||||
{
|
||||
return real_hash (&r.rv ());
|
||||
}
|
|
@ -20,22 +20,16 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "coretypes.h"
|
||||
|
||||
#include "dmd/aggregate.h"
|
||||
#include "dmd/compiler.h"
|
||||
#include "dmd/declaration.h"
|
||||
#include "dmd/errors.h"
|
||||
#include "dmd/expression.h"
|
||||
#include "dmd/identifier.h"
|
||||
#include "dmd/module.h"
|
||||
#include "dmd/mtype.h"
|
||||
#include "dmd/scope.h"
|
||||
#include "dmd/statement.h"
|
||||
#include "dmd/target.h"
|
||||
|
||||
#include "tree.h"
|
||||
#include "options.h"
|
||||
#include "fold-const.h"
|
||||
#include "diagnostic.h"
|
||||
#include "stor-layout.h"
|
||||
|
||||
#include "d-tree.h"
|
||||
|
||||
|
@ -144,416 +138,6 @@ Loc::equals (const Loc& loc)
|
|||
}
|
||||
|
||||
|
||||
/* Implements the Port interface defined by the frontend.
|
||||
A mini library for doing compiler/system specific things. */
|
||||
|
||||
/* Compare the first N bytes of S1 and S2 without regard to the case. */
|
||||
|
||||
int
|
||||
Port::memicmp (const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
char c1 = s1[i];
|
||||
char c2 = s2[i];
|
||||
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
{
|
||||
result = TOUPPER (c1) - TOUPPER (c2);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Convert all characters in S to uppercase. */
|
||||
|
||||
char *
|
||||
Port::strupr (char *s)
|
||||
{
|
||||
char *t = s;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*s = TOUPPER (*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Return true if the real_t value from string BUFFER overflows
|
||||
as a result of rounding down to float mode. */
|
||||
|
||||
bool
|
||||
Port::isFloat32LiteralOutOfRange (const char *buffer)
|
||||
{
|
||||
real_t r;
|
||||
|
||||
real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
|
||||
|
||||
return r == Target::RealProperties::infinity;
|
||||
}
|
||||
|
||||
/* Return true if the real_t value from string BUFFER overflows
|
||||
as a result of rounding down to double mode. */
|
||||
|
||||
bool
|
||||
Port::isFloat64LiteralOutOfRange (const char *buffer)
|
||||
{
|
||||
real_t r;
|
||||
|
||||
real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
|
||||
|
||||
return r == Target::RealProperties::infinity;
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 16-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readwordLE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return ((unsigned) p[1] << 8) | (unsigned) p[0];
|
||||
}
|
||||
|
||||
/* Fetch a big-endian 16-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readwordBE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return ((unsigned) p[0] << 8) | (unsigned) p[1];
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 32-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readlongLE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return (((unsigned) p[3] << 24)
|
||||
| ((unsigned) p[2] << 16)
|
||||
| ((unsigned) p[1] << 8)
|
||||
| (unsigned) p[0]);
|
||||
}
|
||||
|
||||
/* Fetch a big-endian 32-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readlongBE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return (((unsigned) p[0] << 24)
|
||||
| ((unsigned) p[1] << 16)
|
||||
| ((unsigned) p[2] << 8)
|
||||
| (unsigned) p[3]);
|
||||
}
|
||||
|
||||
/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
|
||||
|
||||
void
|
||||
Port::valcpy (void *buffer, uint64_t value, size_t sz)
|
||||
{
|
||||
switch (sz)
|
||||
{
|
||||
case 1:
|
||||
*(uint8_t *) buffer = (uint8_t) value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*(uint16_t *) buffer = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(uint32_t *) buffer = (uint32_t) value;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
*(uint64_t *) buffer = (uint64_t) value;
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Implements the CTFloat interface defined by the frontend.
|
||||
Compile-time floating-pointer helper functions. */
|
||||
|
||||
/* Return the absolute value of R. */
|
||||
|
||||
real_t
|
||||
CTFloat::fabs (real_t r)
|
||||
{
|
||||
real_t x;
|
||||
real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL);
|
||||
return x.normalize ();
|
||||
}
|
||||
|
||||
/* Return the value of R * 2 ^^ EXP. */
|
||||
|
||||
real_t
|
||||
CTFloat::ldexp (real_t r, int exp)
|
||||
{
|
||||
real_t x;
|
||||
real_ldexp (&x.rv (), &r.rv (), exp);
|
||||
return x.normalize ();
|
||||
}
|
||||
|
||||
/* Return true if longdouble value X is identical to Y. */
|
||||
|
||||
bool
|
||||
CTFloat::isIdentical (real_t x, real_t y)
|
||||
{
|
||||
real_value rx = x.rv ();
|
||||
real_value ry = y.rv ();
|
||||
return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
|
||||
|| real_identical (&rx, &ry);
|
||||
}
|
||||
|
||||
/* Return true if real_t value R is NaN. */
|
||||
|
||||
bool
|
||||
CTFloat::isNaN (real_t r)
|
||||
{
|
||||
return REAL_VALUE_ISNAN (r.rv ());
|
||||
}
|
||||
|
||||
/* Same as isNaN, but also check if is signalling. */
|
||||
|
||||
bool
|
||||
CTFloat::isSNaN (real_t r)
|
||||
{
|
||||
return REAL_VALUE_ISSIGNALING_NAN (r.rv ());
|
||||
}
|
||||
|
||||
/* Return true if real_t value is +Inf. */
|
||||
|
||||
bool
|
||||
CTFloat::isInfinity (real_t r)
|
||||
{
|
||||
return REAL_VALUE_ISINF (r.rv ());
|
||||
}
|
||||
|
||||
/* Return a real_t value from string BUFFER rounded to long double mode. */
|
||||
|
||||
real_t
|
||||
CTFloat::parse (const char *buffer, bool *overflow)
|
||||
{
|
||||
real_t r;
|
||||
real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
|
||||
|
||||
/* Front-end checks overflow to see if the value is representable. */
|
||||
if (overflow && r == Target::RealProperties::infinity)
|
||||
*overflow = true;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
|
||||
converting the result to uppercase if FMT requests it. */
|
||||
|
||||
int
|
||||
CTFloat::sprint (char *buffer, char fmt, real_t r)
|
||||
{
|
||||
if (fmt == 'a' || fmt == 'A')
|
||||
{
|
||||
/* Converting to a hexadecimal string. */
|
||||
real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
|
||||
int buflen;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case 'A':
|
||||
buflen = strlen (buffer);
|
||||
for (int i = 0; i < buflen; i++)
|
||||
buffer[i] = TOUPPER (buffer[i]);
|
||||
|
||||
return buflen;
|
||||
|
||||
case 'a':
|
||||
return strlen (buffer);
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note: restricting the precision of significant digits to 18. */
|
||||
real_to_decimal (buffer, &r.rv (), 32, 18, 1);
|
||||
return strlen (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a hash value for real_t value R. */
|
||||
|
||||
size_t
|
||||
CTFloat::hash (real_t r)
|
||||
{
|
||||
return real_hash (&r.rv ());
|
||||
}
|
||||
|
||||
/* Implements the Compiler interface used by the frontend. */
|
||||
|
||||
/* Generate C main() in response to seeing D main(). This used to be in
|
||||
libdruntime, but contained a reference to _Dmain which didn't work when
|
||||
druntime was made into a shared library and was linked to a program, such
|
||||
as a C++ program, that didn't have a _Dmain. */
|
||||
|
||||
void
|
||||
Compiler::genCmain (Scope *sc)
|
||||
{
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
/* The D code to be generated is provided by __entrypoint.di, try to load it,
|
||||
but don't fail if unfound. */
|
||||
unsigned errors = global.startGagging ();
|
||||
Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint"));
|
||||
|
||||
if (global.endGagging (errors))
|
||||
m = NULL;
|
||||
|
||||
if (m != NULL)
|
||||
{
|
||||
m->importedFrom = m;
|
||||
m->importAll (NULL);
|
||||
m->semantic (NULL);
|
||||
m->semantic2 (NULL);
|
||||
m->semantic3 (NULL);
|
||||
d_add_entrypoint_module (m, sc->_module);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
|
||||
The front end should have already ensured that EXPR is a constant,
|
||||
so we just lower the value to GCC and return the converted CST. */
|
||||
|
||||
Expression *
|
||||
Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
|
||||
{
|
||||
/* We support up to 512-bit values. */
|
||||
unsigned char buffer[64];
|
||||
tree cst;
|
||||
|
||||
Type *tb = type->toBasetype ();
|
||||
|
||||
if (expr->type->isintegral ())
|
||||
cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
|
||||
else if (expr->type->isfloating ())
|
||||
cst = build_float_cst (expr->toReal (), expr->type);
|
||||
else if (expr->op == TOKarrayliteral)
|
||||
{
|
||||
/* Build array as VECTOR_CST, assumes EXPR is constant. */
|
||||
Expressions *elements = ((ArrayLiteralExp *) expr)->elements;
|
||||
vec<constructor_elt, va_gc> *elms = NULL;
|
||||
|
||||
vec_safe_reserve (elms, elements->dim);
|
||||
for (size_t i = 0; i < elements->dim; i++)
|
||||
{
|
||||
Expression *e = (*elements)[i];
|
||||
if (e->type->isintegral ())
|
||||
{
|
||||
tree value = build_integer_cst (e->toInteger (),
|
||||
build_ctype (e->type));
|
||||
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
|
||||
}
|
||||
else if (e->type->isfloating ())
|
||||
{
|
||||
tree value = build_float_cst (e->toReal (), e->type);
|
||||
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Build vector type. */
|
||||
int nunits = ((TypeSArray *) expr->type)->dim->toUInteger ();
|
||||
Type *telem = expr->type->nextOf ();
|
||||
tree vectype = build_vector_type (build_ctype (telem), nunits);
|
||||
|
||||
cst = build_vector_from_ctor (vectype, elms);
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
/* Encode CST to buffer. */
|
||||
int len = native_encode_expr (cst, buffer, sizeof (buffer));
|
||||
|
||||
if (tb->ty == Tsarray)
|
||||
{
|
||||
/* Interpret value as a vector of the same size,
|
||||
then return the array literal. */
|
||||
int nunits = ((TypeSArray *) type)->dim->toUInteger ();
|
||||
Type *elem = type->nextOf ();
|
||||
tree vectype = build_vector_type (build_ctype (elem), nunits);
|
||||
|
||||
cst = native_interpret_expr (vectype, buffer, len);
|
||||
|
||||
Expression *e = d_eval_constant_expression (cst);
|
||||
gcc_assert (e != NULL && e->op == TOKvector);
|
||||
|
||||
return ((VectorExp *) e)->e1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal interpret cast. */
|
||||
cst = native_interpret_expr (build_ctype (type), buffer, len);
|
||||
|
||||
Expression *e = d_eval_constant_expression (cst);
|
||||
gcc_assert (e != NULL);
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check imported module M for any special processing.
|
||||
Modules we look out for are:
|
||||
- object: For D runtime type information.
|
||||
- gcc.builtins: For all gcc builtins.
|
||||
- core.stdc.*: For all gcc library builtins. */
|
||||
|
||||
void
|
||||
Compiler::loadModule (Module *m)
|
||||
{
|
||||
ModuleDeclaration *md = m->md;
|
||||
|
||||
if (!md || !md->id || !md->packages)
|
||||
{
|
||||
Identifier *id = (md && md->id) ? md->id : m->ident;
|
||||
if (!strcmp (id->toChars (), "object"))
|
||||
create_tinfo_types (m);
|
||||
}
|
||||
else if (md->packages->dim == 1)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
|
||||
&& !strcmp (md->id->toChars (), "builtins"))
|
||||
d_build_builtins_module (m);
|
||||
}
|
||||
else if (md->packages->dim == 2)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "core")
|
||||
&& !strcmp ((*md->packages)[1]->toChars (), "stdc"))
|
||||
d_add_builtin_module (m);
|
||||
}
|
||||
}
|
||||
|
||||
/* Implements back-end specific interfaces used by the frontend. */
|
||||
|
||||
/* Determine return style of function - whether in registers or through a
|
||||
|
|
169
gcc/d/d-port.cc
Normal file
169
gcc/d/d-port.cc
Normal file
|
@ -0,0 +1,169 @@
|
|||
/* d-port.cc -- D frontend interface to the gcc back-end.
|
||||
Copyright (C) 2013-2020 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/root/port.h"
|
||||
#include "dmd/target.h"
|
||||
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
/* Implements the Port interface defined by the frontend.
|
||||
A mini library for doing compiler/system specific things. */
|
||||
|
||||
/* Compare the first N bytes of S1 and S2 without regard to the case. */
|
||||
|
||||
int
|
||||
Port::memicmp (const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
char c1 = s1[i];
|
||||
char c2 = s2[i];
|
||||
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
{
|
||||
result = TOUPPER (c1) - TOUPPER (c2);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Convert all characters in S to uppercase. */
|
||||
|
||||
char *
|
||||
Port::strupr (char *s)
|
||||
{
|
||||
char *t = s;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*s = TOUPPER (*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Return true if the real_t value from string BUFFER overflows
|
||||
as a result of rounding down to float mode. */
|
||||
|
||||
bool
|
||||
Port::isFloat32LiteralOutOfRange (const char *buffer)
|
||||
{
|
||||
real_t r;
|
||||
|
||||
real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
|
||||
|
||||
return r == Target::RealProperties::infinity;
|
||||
}
|
||||
|
||||
/* Return true if the real_t value from string BUFFER overflows
|
||||
as a result of rounding down to double mode. */
|
||||
|
||||
bool
|
||||
Port::isFloat64LiteralOutOfRange (const char *buffer)
|
||||
{
|
||||
real_t r;
|
||||
|
||||
real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
|
||||
|
||||
return r == Target::RealProperties::infinity;
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 16-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readwordLE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return ((unsigned) p[1] << 8) | (unsigned) p[0];
|
||||
}
|
||||
|
||||
/* Fetch a big-endian 16-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readwordBE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return ((unsigned) p[0] << 8) | (unsigned) p[1];
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 32-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readlongLE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return (((unsigned) p[3] << 24)
|
||||
| ((unsigned) p[2] << 16)
|
||||
| ((unsigned) p[1] << 8)
|
||||
| (unsigned) p[0]);
|
||||
}
|
||||
|
||||
/* Fetch a big-endian 32-bit value from BUFFER. */
|
||||
|
||||
unsigned
|
||||
Port::readlongBE (void *buffer)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) buffer;
|
||||
|
||||
return (((unsigned) p[0] << 24)
|
||||
| ((unsigned) p[1] << 16)
|
||||
| ((unsigned) p[2] << 8)
|
||||
| (unsigned) p[3]);
|
||||
}
|
||||
|
||||
/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
|
||||
|
||||
void
|
||||
Port::valcpy (void *buffer, uint64_t value, size_t sz)
|
||||
{
|
||||
switch (sz)
|
||||
{
|
||||
case 1:
|
||||
*(uint8_t *) buffer = (uint8_t) value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*(uint16_t *) buffer = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(uint32_t *) buffer = (uint32_t) value;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
*(uint64_t *) buffer = (uint64_t) value;
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue