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