1 /* d-frontend.cc -- D frontend interface to the gcc back-end.
2 Copyright (C) 2013-2020 Free Software Foundation, Inc.
3
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)
7 any later version.
8
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.
13
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/>. */
17
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
21
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"
33
34 #include "tree.h"
35 #include "options.h"
36 #include "fold-const.h"
37 #include "diagnostic.h"
38 #include "stor-layout.h"
39
40 #include "d-tree.h"
41
42
43 /* Implements the Global interface defined by the frontend.
44 Used for managing the state of the current compilation. */
45
46 Global global;
47
48 void
_init(void)49 Global::_init (void)
50 {
51 this->mars_ext = "d";
52 this->hdr_ext = "di";
53 this->doc_ext = "html";
54 this->ddoc_ext = "ddoc";
55 this->json_ext = "json";
56 this->obj_ext = "o";
57
58 this->run_noext = true;
59 this->version = "v"
60 #include "verstr.h"
61 ;
62
63 this->stdmsg = stderr;
64 this->errorLimit = flag_max_errors;
65 }
66
67 /* Start gagging. Return the current number of gagged errors. */
68
69 unsigned
startGagging(void)70 Global::startGagging (void)
71 {
72 this->gag++;
73 return this->gaggedErrors;
74 }
75
76 /* End gagging, restoring the old gagged state. Return true if errors
77 occured while gagged. */
78
79 bool
endGagging(unsigned oldGagged)80 Global::endGagging (unsigned oldGagged)
81 {
82 bool anyErrs = (this->gaggedErrors != oldGagged);
83 this->gag--;
84
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;
89
90 return anyErrs;
91 }
92
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. */
95
96 void
increaseErrorCount(void)97 Global::increaseErrorCount (void)
98 {
99 if (gag)
100 this->gaggedErrors++;
101
102 this->errors++;
103 }
104
105
106 /* Implements the Loc interface defined by the frontend.
107 Used for keeping track of current file/line position in code. */
108
Loc(const char * filename,unsigned linnum,unsigned charnum)109 Loc::Loc (const char *filename, unsigned linnum, unsigned charnum)
110 {
111 this->linnum = linnum;
112 this->charnum = charnum;
113 this->filename = filename;
114 }
115
116 const char *
toChars(void) const117 Loc::toChars (void) const
118 {
119 OutBuffer buf;
120
121 if (this->filename)
122 buf.printf ("%s", this->filename);
123
124 if (this->linnum)
125 {
126 buf.printf (":%u", this->linnum);
127 if (this->charnum)
128 buf.printf (":%u", this->charnum);
129 }
130
131 return buf.extractString ();
132 }
133
134 bool
equals(const Loc & loc)135 Loc::equals (const Loc& loc)
136 {
137 if (this->linnum != loc.linnum || this->charnum != loc.charnum)
138 return false;
139
140 if (!FileName::equals (this->filename, loc.filename))
141 return false;
142
143 return true;
144 }
145
146
147 /* Implements the Port interface defined by the frontend.
148 A mini library for doing compiler/system specific things. */
149
150 /* Compare the first N bytes of S1 and S2 without regard to the case. */
151
152 int
memicmp(const char * s1,const char * s2,size_t n)153 Port::memicmp (const char *s1, const char *s2, size_t n)
154 {
155 int result = 0;
156
157 for (size_t i = 0; i < n; i++)
158 {
159 char c1 = s1[i];
160 char c2 = s2[i];
161
162 result = c1 - c2;
163 if (result)
164 {
165 result = TOUPPER (c1) - TOUPPER (c2);
166 if (result)
167 break;
168 }
169 }
170
171 return result;
172 }
173
174 /* Convert all characters in S to uppercase. */
175
176 char *
strupr(char * s)177 Port::strupr (char *s)
178 {
179 char *t = s;
180
181 while (*s)
182 {
183 *s = TOUPPER (*s);
184 s++;
185 }
186
187 return t;
188 }
189
190 /* Return true if the real_t value from string BUFFER overflows
191 as a result of rounding down to float mode. */
192
193 bool
isFloat32LiteralOutOfRange(const char * buffer)194 Port::isFloat32LiteralOutOfRange (const char *buffer)
195 {
196 real_t r;
197
198 real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
199
200 return r == Target::RealProperties::infinity;
201 }
202
203 /* Return true if the real_t value from string BUFFER overflows
204 as a result of rounding down to double mode. */
205
206 bool
isFloat64LiteralOutOfRange(const char * buffer)207 Port::isFloat64LiteralOutOfRange (const char *buffer)
208 {
209 real_t r;
210
211 real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
212
213 return r == Target::RealProperties::infinity;
214 }
215
216 /* Fetch a little-endian 16-bit value from BUFFER. */
217
218 unsigned
readwordLE(void * buffer)219 Port::readwordLE (void *buffer)
220 {
221 unsigned char *p = (unsigned char*) buffer;
222
223 return ((unsigned) p[1] << 8) | (unsigned) p[0];
224 }
225
226 /* Fetch a big-endian 16-bit value from BUFFER. */
227
228 unsigned
readwordBE(void * buffer)229 Port::readwordBE (void *buffer)
230 {
231 unsigned char *p = (unsigned char*) buffer;
232
233 return ((unsigned) p[0] << 8) | (unsigned) p[1];
234 }
235
236 /* Fetch a little-endian 32-bit value from BUFFER. */
237
238 unsigned
readlongLE(void * buffer)239 Port::readlongLE (void *buffer)
240 {
241 unsigned char *p = (unsigned char*) buffer;
242
243 return (((unsigned) p[3] << 24)
244 | ((unsigned) p[2] << 16)
245 | ((unsigned) p[1] << 8)
246 | (unsigned) p[0]);
247 }
248
249 /* Fetch a big-endian 32-bit value from BUFFER. */
250
251 unsigned
readlongBE(void * buffer)252 Port::readlongBE (void *buffer)
253 {
254 unsigned char *p = (unsigned char*) buffer;
255
256 return (((unsigned) p[0] << 24)
257 | ((unsigned) p[1] << 16)
258 | ((unsigned) p[2] << 8)
259 | (unsigned) p[3]);
260 }
261
262 /* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
263
264 void
valcpy(void * buffer,uint64_t value,size_t sz)265 Port::valcpy (void *buffer, uint64_t value, size_t sz)
266 {
267 switch (sz)
268 {
269 case 1:
270 *(uint8_t *) buffer = (uint8_t) value;
271 break;
272
273 case 2:
274 *(uint16_t *) buffer = (uint16_t) value;
275 break;
276
277 case 4:
278 *(uint32_t *) buffer = (uint32_t) value;
279 break;
280
281 case 8:
282 *(uint64_t *) buffer = (uint64_t) value;
283 break;
284
285 default:
286 gcc_unreachable ();
287 }
288 }
289
290
291 /* Implements the CTFloat interface defined by the frontend.
292 Compile-time floating-pointer helper functions. */
293
294 /* Return the absolute value of R. */
295
296 real_t
fabs(real_t r)297 CTFloat::fabs (real_t r)
298 {
299 real_t x;
300 real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL);
301 return x.normalize ();
302 }
303
304 /* Return the value of R * 2 ^^ EXP. */
305
306 real_t
ldexp(real_t r,int exp)307 CTFloat::ldexp (real_t r, int exp)
308 {
309 real_t x;
310 real_ldexp (&x.rv (), &r.rv (), exp);
311 return x.normalize ();
312 }
313
314 /* Return true if longdouble value X is identical to Y. */
315
316 bool
isIdentical(real_t x,real_t y)317 CTFloat::isIdentical (real_t x, real_t y)
318 {
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);
323 }
324
325 /* Return true if real_t value R is NaN. */
326
327 bool
isNaN(real_t r)328 CTFloat::isNaN (real_t r)
329 {
330 return REAL_VALUE_ISNAN (r.rv ());
331 }
332
333 /* Same as isNaN, but also check if is signalling. */
334
335 bool
isSNaN(real_t r)336 CTFloat::isSNaN (real_t r)
337 {
338 return REAL_VALUE_ISSIGNALING_NAN (r.rv ());
339 }
340
341 /* Return true if real_t value is +Inf. */
342
343 bool
isInfinity(real_t r)344 CTFloat::isInfinity (real_t r)
345 {
346 return REAL_VALUE_ISINF (r.rv ());
347 }
348
349 /* Return a real_t value from string BUFFER rounded to long double mode. */
350
351 real_t
parse(const char * buffer,bool * overflow)352 CTFloat::parse (const char *buffer, bool *overflow)
353 {
354 real_t r;
355 real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
356
357 /* Front-end checks overflow to see if the value is representable. */
358 if (overflow && r == Target::RealProperties::infinity)
359 *overflow = true;
360
361 return r;
362 }
363
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. */
366
367 int
sprint(char * buffer,char fmt,real_t r)368 CTFloat::sprint (char *buffer, char fmt, real_t r)
369 {
370 if (fmt == 'a' || fmt == 'A')
371 {
372 /* Converting to a hexadecimal string. */
373 real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
374 int buflen;
375
376 switch (fmt)
377 {
378 case 'A':
379 buflen = strlen (buffer);
380 for (int i = 0; i < buflen; i++)
381 buffer[i] = TOUPPER (buffer[i]);
382
383 return buflen;
384
385 case 'a':
386 return strlen (buffer);
387
388 default:
389 gcc_unreachable ();
390 }
391 }
392 else
393 {
394 /* Note: restricting the precision of significant digits to 18. */
395 real_to_decimal (buffer, &r.rv (), 32, 18, 1);
396 return strlen (buffer);
397 }
398 }
399
400 /* Return a hash value for real_t value R. */
401
402 size_t
hash(real_t r)403 CTFloat::hash (real_t r)
404 {
405 return real_hash (&r.rv ());
406 }
407
408 /* Implements the Compiler interface used by the frontend. */
409
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. */
414
415 void
genCmain(Scope * sc)416 Compiler::genCmain (Scope *sc)
417 {
418 static bool initialized = false;
419
420 if (initialized)
421 return;
422
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"));
427
428 if (global.endGagging (errors))
429 m = NULL;
430
431 if (m != NULL)
432 {
433 m->importedFrom = m;
434 m->importAll (NULL);
435 m->semantic (NULL);
436 m->semantic2 (NULL);
437 m->semantic3 (NULL);
438 d_add_entrypoint_module (m, sc->_module);
439 }
440
441 initialized = true;
442 }
443
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. */
447
448 Expression *
paintAsType(UnionExp *,Expression * expr,Type * type)449 Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
450 {
451 /* We support up to 512-bit values. */
452 unsigned char buffer[64];
453 tree cst;
454
455 Type *tb = type->toBasetype ();
456
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)
462 {
463 /* Build array as VECTOR_CST, assumes EXPR is constant. */
464 Expressions *elements = ((ArrayLiteralExp *) expr)->elements;
465 vec<constructor_elt, va_gc> *elms = NULL;
466
467 vec_safe_reserve (elms, elements->dim);
468 for (size_t i = 0; i < elements->dim; i++)
469 {
470 Expression *e = (*elements)[i];
471 if (e->type->isintegral ())
472 {
473 tree value = build_integer_cst (e->toInteger (),
474 build_ctype (e->type));
475 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
476 }
477 else if (e->type->isfloating ())
478 {
479 tree value = build_float_cst (e->toReal (), e->type);
480 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
481 }
482 else
483 gcc_unreachable ();
484 }
485
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);
490
491 cst = build_vector_from_ctor (vectype, elms);
492 }
493 else
494 gcc_unreachable ();
495
496 /* Encode CST to buffer. */
497 int len = native_encode_expr (cst, buffer, sizeof (buffer));
498
499 if (tb->ty == Tsarray)
500 {
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);
506
507 cst = native_interpret_expr (vectype, buffer, len);
508
509 Expression *e = d_eval_constant_expression (cst);
510 gcc_assert (e != NULL && e->op == TOKvector);
511
512 return ((VectorExp *) e)->e1;
513 }
514 else
515 {
516 /* Normal interpret cast. */
517 cst = native_interpret_expr (build_ctype (type), buffer, len);
518
519 Expression *e = d_eval_constant_expression (cst);
520 gcc_assert (e != NULL);
521
522 return e;
523 }
524 }
525
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. */
531
532 void
loadModule(Module * m)533 Compiler::loadModule (Module *m)
534 {
535 ModuleDeclaration *md = m->md;
536
537 if (!md || !md->id || !md->packages)
538 {
539 Identifier *id = (md && md->id) ? md->id : m->ident;
540 if (!strcmp (id->toChars (), "object"))
541 create_tinfo_types (m);
542 }
543 else if (md->packages->dim == 1)
544 {
545 if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
546 && !strcmp (md->id->toChars (), "builtins"))
547 d_build_builtins_module (m);
548 }
549 else if (md->packages->dim == 2)
550 {
551 if (!strcmp ((*md->packages)[0]->toChars (), "core")
552 && !strcmp ((*md->packages)[1]->toChars (), "stdc"))
553 d_add_builtin_module (m);
554 }
555 }
556
557 /* Implements back-end specific interfaces used by the frontend. */
558
559 /* Determine return style of function - whether in registers or through a
560 hidden pointer to the caller's stack. */
561
562 RET
retStyle(TypeFunction *)563 retStyle (TypeFunction *)
564 {
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. */
568 return RETstack;
569 }
570
571 /* Determine if function FD is a builtin one that we can evaluate in CTFE. */
572
573 BUILTIN
isBuiltin(FuncDeclaration * fd)574 isBuiltin (FuncDeclaration *fd)
575 {
576 if (fd->builtin != BUILTINunknown)
577 return fd->builtin;
578
579 maybe_set_intrinsic (fd);
580
581 return fd->builtin;
582 }
583
584 /* Evaluate builtin D function FD whose argument list is ARGUMENTS.
585 Return result; NULL if cannot evaluate it. */
586
587 Expression *
eval_builtin(Loc loc,FuncDeclaration * fd,Expressions * arguments)588 eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
589 {
590 if (fd->builtin != BUILTINyes)
591 return NULL;
592
593 tree decl = get_symbol_decl (fd);
594 gcc_assert (fndecl_built_in_p (decl)
595 || DECL_INTRINSIC_CODE (decl) != INTRINSIC_NONE);
596
597 TypeFunction *tf = (TypeFunction *) fd->type;
598 Expression *e = NULL;
599 input_location = make_location_t (loc);
600
601 tree result = d_build_call (tf, decl, NULL, arguments);
602 result = fold (result);
603
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);
608
609 return e;
610 }
611
612 /* Build and return typeinfo type for TYPE. */
613
614 Type *
getTypeInfoType(Loc loc,Type * type,Scope * sc)615 getTypeInfoType (Loc loc, Type *type, Scope *sc)
616 {
617 gcc_assert (type->ty != Terror);
618 check_typeinfo_type (loc, sc);
619 create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
620 return type->vtinfo->type;
621 }
622
623 /* Return an inlined copy of a default argument for a function parameter. */
624
625 Expression *
inlineCopy(Expression * e,Scope *)626 inlineCopy (Expression *e, Scope *)
627 {
628 return e->copy ();
629 }
630