]>
Commit | Line | Data |
---|---|---|
b4c522fa | 1 | /* d-frontend.cc -- D frontend interface to the gcc back-end. |
a5544970 | 2 | Copyright (C) 2013-2019 Free Software Foundation, Inc. |
b4c522fa IB |
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 | |
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 | |
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 | |
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 | |
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 | ||
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 * | |
117 | 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 | |
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 | |
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 * | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 * | |
255b2d91 | 449 | Compiler::paintAsType (UnionExp *, Expression *expr, Type *type) |
b4c522fa IB |
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 | |
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 | |
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 | |
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 * | |
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 * | |
615 | getTypeInfoType (Type *type, Scope *sc) | |
616 | { | |
617 | gcc_assert (type->ty != Terror); | |
618 | create_typeinfo (type, sc ? sc->_module->importedFrom : NULL); | |
619 | return type->vtinfo->type; | |
620 | } | |
621 | ||
622 | /* Return an inlined copy of a default argument for a function parameter. */ | |
623 | ||
624 | Expression * | |
625 | inlineCopy (Expression *e, Scope *) | |
626 | { | |
627 | return e->copy (); | |
628 | } |