1 /* d-frontend.cc -- D frontend interface to the gcc back-end.
2 Copyright (C) 2013-2018 Free Software Foundation, Inc.
4 GCC is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
9 GCC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with GCC; see the file COPYING3. If not see
16 <http://www.gnu.org/licenses/>. */
20 #include "coretypes.h"
22 #include "dmd/aggregate.h"
23 #include "dmd/compiler.h"
24 #include "dmd/declaration.h"
25 #include "dmd/errors.h"
26 #include "dmd/expression.h"
27 #include "dmd/identifier.h"
28 #include "dmd/module.h"
29 #include "dmd/mtype.h"
30 #include "dmd/scope.h"
31 #include "dmd/statement.h"
32 #include "dmd/target.h"
36 #include "fold-const.h"
37 #include "diagnostic.h"
38 #include "stor-layout.h"
43 /* Implements the Global interface defined by the frontend.
44 Used for managing the state of the current compilation. */
53 this->doc_ext
= "html";
54 this->ddoc_ext
= "ddoc";
55 this->json_ext
= "json";
58 this->run_noext
= true;
63 this->stdmsg
= stderr
;
64 this->errorLimit
= flag_max_errors
;
67 /* Start gagging. Return the current number of gagged errors. */
70 Global::startGagging (void)
73 return this->gaggedErrors
;
76 /* End gagging, restoring the old gagged state. Return true if errors
77 occured while gagged. */
80 Global::endGagging (unsigned oldGagged
)
82 bool anyErrs
= (this->gaggedErrors
!= oldGagged
);
85 /* Restore the original state of gagged errors; set total errors
86 to be original errors + new ungagged errors. */
87 this->errors
-= (this->gaggedErrors
- oldGagged
);
88 this->gaggedErrors
= oldGagged
;
93 /* Increment the error count to record that an error has occured in the
94 current context. An error message may or may not have been printed. */
97 Global::increaseErrorCount (void)
100 this->gaggedErrors
++;
106 /* Implements the Loc interface defined by the frontend.
107 Used for keeping track of current file/line position in code. */
109 Loc::Loc (const char *filename
, unsigned linnum
, unsigned charnum
)
111 this->linnum
= linnum
;
112 this->charnum
= charnum
;
113 this->filename
= filename
;
117 Loc::toChars (void) const
122 buf
.printf ("%s", this->filename
);
126 buf
.printf (":%u", this->linnum
);
128 buf
.printf (":%u", this->charnum
);
131 return buf
.extractString ();
135 Loc::equals (const Loc
& loc
)
137 if (this->linnum
!= loc
.linnum
|| this->charnum
!= loc
.charnum
)
140 if (!FileName::equals (this->filename
, loc
.filename
))
147 /* Implements the Port interface defined by the frontend.
148 A mini library for doing compiler/system specific things. */
150 /* Compare the first N bytes of S1 and S2 without regard to the case. */
153 Port::memicmp (const char *s1
, const char *s2
, size_t n
)
157 for (size_t i
= 0; i
< n
; i
++)
165 result
= TOUPPER (c1
) - TOUPPER (c2
);
174 /* Convert all characters in S to uppercase. */
177 Port::strupr (char *s
)
190 /* Return true if the real_t value from string BUFFER overflows
191 as a result of rounding down to float mode. */
194 Port::isFloat32LiteralOutOfRange (const char *buffer
)
198 real_from_string3 (&r
.rv (), buffer
, TYPE_MODE (float_type_node
));
200 return r
== Target::RealProperties::infinity
;
203 /* Return true if the real_t value from string BUFFER overflows
204 as a result of rounding down to double mode. */
207 Port::isFloat64LiteralOutOfRange (const char *buffer
)
211 real_from_string3 (&r
.rv (), buffer
, TYPE_MODE (double_type_node
));
213 return r
== Target::RealProperties::infinity
;
216 /* Fetch a little-endian 16-bit value from BUFFER. */
219 Port::readwordLE (void *buffer
)
221 unsigned char *p
= (unsigned char*) buffer
;
223 return ((unsigned) p
[1] << 8) | (unsigned) p
[0];
226 /* Fetch a big-endian 16-bit value from BUFFER. */
229 Port::readwordBE (void *buffer
)
231 unsigned char *p
= (unsigned char*) buffer
;
233 return ((unsigned) p
[0] << 8) | (unsigned) p
[1];
236 /* Fetch a little-endian 32-bit value from BUFFER. */
239 Port::readlongLE (void *buffer
)
241 unsigned char *p
= (unsigned char*) buffer
;
243 return (((unsigned) p
[3] << 24)
244 | ((unsigned) p
[2] << 16)
245 | ((unsigned) p
[1] << 8)
249 /* Fetch a big-endian 32-bit value from BUFFER. */
252 Port::readlongBE (void *buffer
)
254 unsigned char *p
= (unsigned char*) buffer
;
256 return (((unsigned) p
[0] << 24)
257 | ((unsigned) p
[1] << 16)
258 | ((unsigned) p
[2] << 8)
262 /* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
265 Port::valcpy (void *buffer
, uint64_t value
, size_t sz
)
270 *(uint8_t *) buffer
= (uint8_t) value
;
274 *(uint16_t *) buffer
= (uint16_t) value
;
278 *(uint32_t *) buffer
= (uint32_t) value
;
282 *(uint64_t *) buffer
= (uint64_t) value
;
291 /* Implements the CTFloat interface defined by the frontend.
292 Compile-time floating-pointer helper functions. */
294 /* Return the absolute value of R. */
297 CTFloat::fabs (real_t r
)
300 real_arithmetic (&x
.rv (), ABS_EXPR
, &r
.rv (), NULL
);
301 return x
.normalize ();
304 /* Return the value of R * 2 ^^ EXP. */
307 CTFloat::ldexp (real_t r
, int exp
)
310 real_ldexp (&x
.rv (), &r
.rv (), exp
);
311 return x
.normalize ();
314 /* Return true if longdouble value X is identical to Y. */
317 CTFloat::isIdentical (real_t x
, real_t y
)
319 real_value rx
= x
.rv ();
320 real_value ry
= y
.rv ();
321 return (REAL_VALUE_ISNAN (rx
) && REAL_VALUE_ISNAN (ry
))
322 || real_identical (&rx
, &ry
);
325 /* Return true if real_t value R is NaN. */
328 CTFloat::isNaN (real_t r
)
330 return REAL_VALUE_ISNAN (r
.rv ());
333 /* Same as isNaN, but also check if is signalling. */
336 CTFloat::isSNaN (real_t r
)
338 return REAL_VALUE_ISSIGNALING_NAN (r
.rv ());
341 /* Return true if real_t value is +Inf. */
344 CTFloat::isInfinity (real_t r
)
346 return REAL_VALUE_ISINF (r
.rv ());
349 /* Return a real_t value from string BUFFER rounded to long double mode. */
352 CTFloat::parse (const char *buffer
, bool *overflow
)
355 real_from_string3 (&r
.rv (), buffer
, TYPE_MODE (long_double_type_node
));
357 /* Front-end checks overflow to see if the value is representable. */
358 if (overflow
&& r
== Target::RealProperties::infinity
)
364 /* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
365 converting the result to uppercase if FMT requests it. */
368 CTFloat::sprint (char *buffer
, char fmt
, real_t r
)
370 if (fmt
== 'a' || fmt
== 'A')
372 /* Converting to a hexadecimal string. */
373 real_to_hexadecimal (buffer
, &r
.rv (), 32, 0, 1);
379 buflen
= strlen (buffer
);
380 for (int i
= 0; i
< buflen
; i
++)
381 buffer
[i
] = TOUPPER (buffer
[i
]);
386 return strlen (buffer
);
394 /* Note: restricting the precision of significant digits to 18. */
395 real_to_decimal (buffer
, &r
.rv (), 32, 18, 1);
396 return strlen (buffer
);
400 /* Return a hash value for real_t value R. */
403 CTFloat::hash (real_t r
)
405 return real_hash (&r
.rv ());
408 /* Implements the Compiler interface used by the frontend. */
410 /* Generate C main() in response to seeing D main(). This used to be in
411 libdruntime, but contained a reference to _Dmain which didn't work when
412 druntime was made into a shared library and was linked to a program, such
413 as a C++ program, that didn't have a _Dmain. */
416 Compiler::genCmain (Scope
*sc
)
418 static bool initialized
= false;
423 /* The D code to be generated is provided by __entrypoint.di, try to load it,
424 but don't fail if unfound. */
425 unsigned errors
= global
.startGagging ();
426 Module
*m
= Module::load (Loc (), NULL
, Identifier::idPool ("__entrypoint"));
428 if (global
.endGagging (errors
))
438 d_add_entrypoint_module (m
, sc
->_module
);
444 /* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
445 The front end should have already ensured that EXPR is a constant,
446 so we just lower the value to GCC and return the converted CST. */
449 Compiler::paintAsType (Expression
*expr
, Type
*type
)
451 /* We support up to 512-bit values. */
452 unsigned char buffer
[64];
455 Type
*tb
= type
->toBasetype ();
457 if (expr
->type
->isintegral ())
458 cst
= build_integer_cst (expr
->toInteger (), build_ctype (expr
->type
));
459 else if (expr
->type
->isfloating ())
460 cst
= build_float_cst (expr
->toReal (), expr
->type
);
461 else if (expr
->op
== TOKarrayliteral
)
463 /* Build array as VECTOR_CST, assumes EXPR is constant. */
464 Expressions
*elements
= ((ArrayLiteralExp
*) expr
)->elements
;
465 vec
<constructor_elt
, va_gc
> *elms
= NULL
;
467 vec_safe_reserve (elms
, elements
->dim
);
468 for (size_t i
= 0; i
< elements
->dim
; i
++)
470 Expression
*e
= (*elements
)[i
];
471 if (e
->type
->isintegral ())
473 tree value
= build_integer_cst (e
->toInteger (),
474 build_ctype (e
->type
));
475 CONSTRUCTOR_APPEND_ELT (elms
, size_int (i
), value
);
477 else if (e
->type
->isfloating ())
479 tree value
= build_float_cst (e
->toReal (), e
->type
);
480 CONSTRUCTOR_APPEND_ELT (elms
, size_int (i
), value
);
486 /* Build vector type. */
487 int nunits
= ((TypeSArray
*) expr
->type
)->dim
->toUInteger ();
488 Type
*telem
= expr
->type
->nextOf ();
489 tree vectype
= build_vector_type (build_ctype (telem
), nunits
);
491 cst
= build_vector_from_ctor (vectype
, elms
);
496 /* Encode CST to buffer. */
497 int len
= native_encode_expr (cst
, buffer
, sizeof (buffer
));
499 if (tb
->ty
== Tsarray
)
501 /* Interpret value as a vector of the same size,
502 then return the array literal. */
503 int nunits
= ((TypeSArray
*) type
)->dim
->toUInteger ();
504 Type
*elem
= type
->nextOf ();
505 tree vectype
= build_vector_type (build_ctype (elem
), nunits
);
507 cst
= native_interpret_expr (vectype
, buffer
, len
);
509 Expression
*e
= d_eval_constant_expression (cst
);
510 gcc_assert (e
!= NULL
&& e
->op
== TOKvector
);
512 return ((VectorExp
*) e
)->e1
;
516 /* Normal interpret cast. */
517 cst
= native_interpret_expr (build_ctype (type
), buffer
, len
);
519 Expression
*e
= d_eval_constant_expression (cst
);
520 gcc_assert (e
!= NULL
);
526 /* Check imported module M for any special processing.
527 Modules we look out for are:
528 - object: For D runtime type information.
529 - gcc.builtins: For all gcc builtins.
530 - core.stdc.*: For all gcc library builtins. */
533 Compiler::loadModule (Module
*m
)
535 ModuleDeclaration
*md
= m
->md
;
537 if (!md
|| !md
->id
|| !md
->packages
)
539 Identifier
*id
= (md
&& md
->id
) ? md
->id
: m
->ident
;
540 if (!strcmp (id
->toChars (), "object"))
541 create_tinfo_types (m
);
543 else if (md
->packages
->dim
== 1)
545 if (!strcmp ((*md
->packages
)[0]->toChars (), "gcc")
546 && !strcmp (md
->id
->toChars (), "builtins"))
547 d_build_builtins_module (m
);
549 else if (md
->packages
->dim
== 2)
551 if (!strcmp ((*md
->packages
)[0]->toChars (), "core")
552 && !strcmp ((*md
->packages
)[1]->toChars (), "stdc"))
553 d_add_builtin_module (m
);
557 /* Implements back-end specific interfaces used by the frontend. */
559 /* Determine return style of function - whether in registers or through a
560 hidden pointer to the caller's stack. */
563 retStyle (TypeFunction
*)
565 /* Need the backend type to determine this, but this is called from the
566 frontend before semantic processing is finished. An accurate value
567 is not currently needed anyway. */
571 /* Determine if function FD is a builtin one that we can evaluate in CTFE. */
574 isBuiltin (FuncDeclaration
*fd
)
576 if (fd
->builtin
!= BUILTINunknown
)
579 maybe_set_intrinsic (fd
);
584 /* Evaluate builtin D function FD whose argument list is ARGUMENTS.
585 Return result; NULL if cannot evaluate it. */
588 eval_builtin (Loc loc
, FuncDeclaration
*fd
, Expressions
*arguments
)
590 if (fd
->builtin
!= BUILTINyes
)
593 tree decl
= get_symbol_decl (fd
);
594 gcc_assert (fndecl_built_in_p (decl
)
595 || DECL_INTRINSIC_CODE (decl
) != INTRINSIC_NONE
);
597 TypeFunction
*tf
= (TypeFunction
*) fd
->type
;
598 Expression
*e
= NULL
;
599 input_location
= make_location_t (loc
);
601 tree result
= d_build_call (tf
, decl
, NULL
, arguments
);
602 result
= fold (result
);
604 /* Builtin should be successfully evaluated.
605 Will only return NULL if we can't convert it. */
606 if (TREE_CONSTANT (result
) && TREE_CODE (result
) != CALL_EXPR
)
607 e
= d_eval_constant_expression (result
);
612 /* Build and return typeinfo type for TYPE. */
615 getTypeInfoType (Type
*type
, Scope
*sc
)
617 gcc_assert (type
->ty
!= Terror
);
618 create_typeinfo (type
, sc
? sc
->_module
->importedFrom
: NULL
);
619 return type
->vtinfo
->type
;
622 /* Return an inlined copy of a default argument for a function parameter. */
625 inlineCopy (Expression
*e
, Scope
*)