1 /* d-target.cc -- Target interface for the D front end.
2    Copyright (C) 2013-2021 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/declaration.h"
24 #include "dmd/expression.h"
25 #include "dmd/mangle.h"
26 #include "dmd/mtype.h"
27 #include "dmd/tokens.h"
28 #include "dmd/target.h"
29 
30 #include "tree.h"
31 #include "memmodel.h"
32 #include "fold-const.h"
33 #include "diagnostic.h"
34 #include "stor-layout.h"
35 #include "tm.h"
36 #include "tm_p.h"
37 #include "target.h"
38 #include "calls.h"
39 
40 #include "d-tree.h"
41 #include "d-target.h"
42 
43 /* Implements the Target interface defined by the front end.
44    Used for retrieving target-specific information.  */
45 
46 /* Internal key handlers for `__traits(getTargetInfo)'.  */
47 static tree d_handle_target_cpp_std (void);
48 static tree d_handle_target_cpp_runtime_library (void);
49 static tree d_handle_target_object_format (void);
50 
51 /* In [traits/getTargetInfo], a reliable subset of getTargetInfo keys exists
52    which are always available.  */
53 static const struct d_target_info_spec d_language_target_info[] =
54 {
55   /* { name, handler } */
56   { "cppStd", d_handle_target_cpp_std },
57   { "cppRuntimeLibrary", d_handle_target_cpp_runtime_library },
58   { "floatAbi", NULL },
59   { "objectFormat", d_handle_target_object_format },
60   { NULL, NULL },
61 };
62 
63 /* Table `__traits(getTargetInfo)' keys.  */
64 static vec<d_target_info_spec> d_target_info_table;
65 
66 
67 /* Initialize the floating-point constants for TYPE.  */
68 
69 template <typename T>
70 static void
define_float_constants(T & f,tree type)71 define_float_constants (T &f, tree type)
72 {
73   const double log10_2 = 0.30102999566398119521;
74   char buf[128];
75 
76   /* Get back-end real mode format.  */
77   const machine_mode mode = TYPE_MODE (type);
78   const real_format *fmt = REAL_MODE_FORMAT (mode);
79 
80   /* The largest representable value that's not infinity.  */
81   get_max_float (fmt, buf, sizeof (buf), false);
82   real_from_string (&f.max.rv (), buf);
83 
84   /* The smallest representable normalized value that's not 0.  */
85   snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - 1);
86   real_from_string (&f.min_normal.rv (), buf);
87 
88   /* Floating-point NaN.  */
89   real_nan (&f.nan.rv (), "", 1, mode);
90 
91   /* Floating-point +Infinity if the target supports infinities.  */
92   real_inf (&f.infinity.rv ());
93 
94   /* The smallest increment to the value 1.  */
95   if (fmt->pnan < fmt->p)
96     snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - fmt->p);
97   else
98     snprintf (buf, sizeof (buf), "0x1p%d", 1 - fmt->p);
99   real_from_string (&f.epsilon.rv (), buf);
100 
101   /* The number of decimal digits of precision.  */
102   f.dig = (fmt->p - 1) * log10_2;
103 
104   /* The number of bits in mantissa.  */
105   f.mant_dig = fmt->p;
106 
107   /* The maximum int value such that 2** (value-1) is representable.  */
108   f.max_exp = fmt->emax;
109 
110   /* The minimum int value such that 2** (value-1) is representable as a
111      normalized value.  */
112   f.min_exp = fmt->emin;
113 
114   /* The maximum int value such that 10**value is representable.  */
115   f.max_10_exp = fmt->emax * log10_2;
116 
117   /* The minimum int value such that 10**value is representable as a
118      normalized value.  */
119   f.min_10_exp = (fmt->emin - 1) * log10_2;
120 }
121 
122 /* Initialize all variables of the Target structure.  */
123 
124 void
_init(const Param &)125 Target::_init (const Param &)
126 {
127   /* Map D frontend type and sizes to GCC back-end types.  */
128   this->ptrsize = (POINTER_SIZE / BITS_PER_UNIT);
129   this->realsize = int_size_in_bytes (long_double_type_node);
130   this->realpad = (this->realsize -
131 		   (TYPE_PRECISION (long_double_type_node) / BITS_PER_UNIT));
132   this->realalignsize = TYPE_ALIGN_UNIT (long_double_type_node);
133 
134   /* Much of the dmd front-end uses ints for sizes and offsets, and cannot
135      handle any larger data type without some pervasive rework.  */
136   this->maxStaticDataSize = tree_to_shwi (TYPE_MAX_VALUE (integer_type_node));
137 
138   /* Define what type to use for size_t, ptrdiff_t.  */
139   if (this->ptrsize == 8)
140     {
141       this->isLP64 = true;
142       Type::tsize_t = Type::basic[(int)TY::Tuns64];
143       Type::tptrdiff_t = Type::basic[(int)TY::Tint64];
144     }
145   else if (this->ptrsize == 4)
146     {
147       Type::tsize_t = Type::basic[(int)TY::Tuns32];
148       Type::tptrdiff_t = Type::basic[(int)TY::Tint32];
149     }
150   else if (this->ptrsize == 2)
151     {
152       Type::tsize_t = Type::basic[(int)TY::Tuns16];
153       Type::tptrdiff_t = Type::basic[(int)TY::Tint16];
154     }
155   else
156     sorry ("D does not support pointers on this target.");
157 
158   Type::thash_t = Type::tsize_t;
159 
160   /* Set-up target C ABI.  */
161   this->c.longsize = int_size_in_bytes (long_integer_type_node);
162   this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
163   this->c.wchar_tsize = (WCHAR_TYPE_SIZE / BITS_PER_UNIT);
164 
165   /* Set-up target C++ ABI.  */
166   this->cpp.reverseOverloads = false;
167   this->cpp.exceptions = true;
168   this->cpp.twoDtorInVtable = true;
169 
170   /* Set-up target Objective-C ABI.  */
171   this->objc.supported = false;
172 
173   /* Set-up environmental settings.  */
174   this->obj_ext = "o";
175   this->lib_ext = "a";
176   this->dll_ext = "so";
177   this->run_noext = true;
178 
179   /* Initialize all compile-time properties for floating-point types.
180      Should ensure that our real_t type is able to represent real_value.  */
181   gcc_assert (sizeof (real_t) >= sizeof (real_value));
182 
183   define_float_constants (this->FloatProperties, float_type_node);
184   define_float_constants (this->DoubleProperties, double_type_node);
185   define_float_constants (this->RealProperties, long_double_type_node);
186 
187   /* Commonly used floating-point constants.  */
188   const machine_mode mode = TYPE_MODE (long_double_type_node);
189   real_convert (&CTFloat::zero.rv (), mode, &dconst0);
190   real_convert (&CTFloat::one.rv (), mode, &dconst1);
191   real_convert (&CTFloat::minusone.rv (), mode, &dconstm1);
192   real_convert (&CTFloat::half.rv (), mode, &dconsthalf);
193 
194   /* Initialize target info tables, the keys required by the language are added
195      last, so that the OS and CPU handlers can override.  */
196   targetdm.d_register_cpu_target_info ();
197   targetdm.d_register_os_target_info ();
198   d_add_target_info_handlers (d_language_target_info);
199 }
200 
201 /* Return GCC memory alignment size for type TYPE.  */
202 
203 unsigned
alignsize(Type * type)204 Target::alignsize (Type *type)
205 {
206   gcc_assert (type->isTypeBasic ());
207   return min_align_of_type (build_ctype (type));
208 }
209 
210 /* Return GCC field alignment size for type TYPE.  */
211 
212 unsigned
fieldalign(Type * type)213 Target::fieldalign (Type *type)
214 {
215   /* Work out the correct alignment for the field decl.  */
216   unsigned int align = type->alignsize () * BITS_PER_UNIT;
217 
218 #ifdef BIGGEST_FIELD_ALIGNMENT
219   align = MIN (align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
220 #endif
221 
222 #ifdef ADJUST_FIELD_ALIGN
223   if (type->isTypeBasic ())
224     align = ADJUST_FIELD_ALIGN (NULL_TREE, build_ctype (type), align);
225 #endif
226 
227   /* Also controlled by -fpack-struct=  */
228   if (maximum_field_alignment)
229     align = MIN (align, maximum_field_alignment);
230 
231   return align / BITS_PER_UNIT;
232 }
233 
234 /* Returns a Type for the va_list type of the target.  */
235 
236 Type *
va_listType(const Loc &,Scope *)237 Target::va_listType (const Loc &, Scope *)
238 {
239   if (this->tvalist)
240     return this->tvalist;
241 
242   /* Build the "standard" abi va_list.  */
243   this->tvalist = build_frontend_type (va_list_type_node);
244   if (!this->tvalist)
245     sorry ("cannot represent built-in %<va_list%> type in D");
246 
247   /* Map the va_list type to the D frontend Type.  This is to prevent both
248      errors in gimplification or an ICE in targetm.canonical_va_list_type.  */
249   this->tvalist->ctype = va_list_type_node;
250   TYPE_LANG_SPECIFIC (va_list_type_node) = build_lang_type (this->tvalist);
251 
252   return this->tvalist;
253 }
254 
255 /* Checks whether the target supports a vector type with total size SZ
256    (in bytes) and element type TYPE.  */
257 
258 int
isVectorTypeSupported(int sz,Type * type)259 Target::isVectorTypeSupported (int sz, Type *type)
260 {
261   /* Size must be greater than zero, and a power of two.  */
262   if (sz <= 0 || sz & (sz - 1))
263     return 3;
264 
265   /* __vector(void[]) is treated same as __vector(ubyte[])  */
266   if (type == Type::tvoid)
267     type = Type::tuns8;
268 
269   /* No support for non-trivial types, complex types, or booleans.  */
270   if (!type->isTypeBasic () || type->iscomplex () || type->ty == TY::Tbool)
271     return 2;
272 
273   /* In [simd/vector extensions], which vector types are supported depends on
274      the target.  The implementation is expected to only support the vector
275      types that are implemented in the target's hardware.  */
276   unsigned HOST_WIDE_INT nunits = sz / type->size ();
277   tree ctype = build_vector_type (build_ctype (type), nunits);
278 
279   if (!targetm.vector_mode_supported_p (TYPE_MODE (ctype)))
280     return 2;
281 
282   return 0;
283 }
284 
285 /* Checks whether the target supports operation OP for vectors of type TYPE.
286    For binary ops T2 is the type of the right-hand operand.
287    Returns true if the operation is supported or type is not a vector.  */
288 
289 bool
isVectorOpSupported(Type * type,unsigned op,Type *)290 Target::isVectorOpSupported (Type *type, unsigned op, Type *)
291 {
292   if (type->ty != TY::Tvector)
293     return true;
294 
295   /* Don't support if type is non-scalar, such as __vector(void[]).  */
296   if (!type->isscalar ())
297     return false;
298 
299   /* Don't support if expression cannot be represented.  */
300   switch (op)
301     {
302     case TOKpow:
303     case TOKpowass:
304       /* pow() is lowered as a function call.  */
305       return false;
306 
307     case TOKmod:
308     case TOKmodass:
309       /* fmod() is lowered as a function call.  */
310       if (type->isfloating ())
311 	return false;
312       break;
313 
314     case TOKandand:
315     case TOKoror:
316       /* Logical operators must have a result type of bool.  */
317       return false;
318 
319     case TOKle:
320     case TOKlt:
321     case TOKge:
322     case TOKgt:
323     case TOKequal:
324     case TOKnotequal:
325     case TOKidentity:
326     case TOKnotidentity:
327       /* Comparison operators must have a result type of bool.  */
328       return false;
329 
330     default:
331       break;
332     }
333 
334   return true;
335 }
336 
337 /* Return the symbol mangling of S for C++ linkage.  */
338 
339 const char *
toMangle(Dsymbol * s)340 TargetCPP::toMangle (Dsymbol *s)
341 {
342   return toCppMangleItanium (s);
343 }
344 
345 /* Return the symbol mangling of CD for C++ linkage.  */
346 
347 const char *
typeInfoMangle(ClassDeclaration * cd)348 TargetCPP::typeInfoMangle (ClassDeclaration *cd)
349 {
350   return cppTypeInfoMangleItanium (cd);
351 }
352 
353 /* Get mangle name of a this-adjusting thunk to the function declaration FD
354    at call offset OFFSET for C++ linkage.  */
355 
356 const char *
thunkMangle(FuncDeclaration * fd,int offset)357 TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
358 {
359   return cppThunkMangleItanium (fd, offset);
360 }
361 
362 /* For a vendor-specific type, return a string containing the C++ mangling.
363    In all other cases, return NULL.  */
364 
365 const char *
typeMangle(Type * type)366 TargetCPP::typeMangle (Type *type)
367 {
368   if (type->isTypeBasic () || type->ty == TY::Tvector
369       || type->ty == TY::Tstruct)
370     {
371       tree ctype = build_ctype (type);
372       return targetm.mangle_type (ctype);
373     }
374 
375   return NULL;
376 }
377 
378 /* Return the type that will really be used for passing the given parameter
379    ARG to an extern(C++) function.  */
380 
381 Type *
parameterType(Parameter * arg)382 TargetCPP::parameterType (Parameter *arg)
383 {
384   Type *t = arg->type->merge2 ();
385   if (arg->storageClass & (STCout | STCref))
386     t = t->referenceTo ();
387   else if (arg->storageClass & STClazy)
388     {
389       /* Mangle as delegate.  */
390       TypeFunction *tf = TypeFunction::create (NULL, t, VARARGnone, LINK::d);
391       TypeDelegate *td = TypeDelegate::create (tf);
392       t = td->merge2 ();
393     }
394 
395   /* Could be a va_list, which we mangle as a pointer.  */
396   Type *tvalist = target.va_listType (Loc (), NULL);
397   if (t->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
398     {
399       Type *tb = t->toBasetype ()->mutableOf ();
400       if (tb == tvalist)
401 	{
402 	  tb = t->nextOf ()->pointerTo ();
403 	  t = tb->castMod (t->mod);
404 	}
405     }
406 
407   return t;
408 }
409 
410 /* Checks whether TYPE is a vendor-specific fundamental type.  Stores the result
411    in IS_FUNDAMENTAL and returns true if the parameter was set.  */
412 
413 bool
fundamentalType(const Type *,bool &)414 TargetCPP::fundamentalType (const Type *, bool &)
415 {
416   return false;
417 }
418 
419 /* Get the starting offset position for fields of an `extern(C++)` class
420    that is derived from the given BASE_CLASS.  */
421 
422 unsigned
derivedClassOffset(ClassDeclaration * base_class)423 TargetCPP::derivedClassOffset(ClassDeclaration *base_class)
424 {
425   return base_class->structsize;
426 }
427 
428 /* Return the default `extern (System)' linkage for the target.  */
429 
430 LINK
systemLinkage(void)431 Target::systemLinkage (void)
432 {
433   unsigned link_system, link_windows;
434 
435   if (targetdm.d_has_stdcall_convention (&link_system, &link_windows))
436     {
437       /* In [attribute/linkage], `System' is the same as `Windows' on Windows
438 	 platforms, and `C' on other platforms.  */
439       if (link_system)
440 	return LINK::windows;
441     }
442 
443   return LINK::c;
444 }
445 
446 /* Generate a TypeTuple of the equivalent types used to determine if a
447    function argument of the given type can be passed in registers.
448    The results of this are highly platform dependent, and intended
449    primarly for use in implementing va_arg() with RTTI.  */
450 
451 TypeTuple *
toArgTypes(Type *)452 Target::toArgTypes (Type *)
453 {
454   /* Not implemented, however this is not currently used anywhere.  */
455   return NULL;
456 }
457 
458 /* Determine return style of function, whether in registers or through a
459    hidden pointer to the caller's stack.  */
460 
461 bool
isReturnOnStack(TypeFunction * tf,bool)462 Target::isReturnOnStack (TypeFunction *tf, bool)
463 {
464   /* Need the back-end type to determine this, but this is called from the
465      frontend before semantic processing is finished.  An accurate value
466      is not currently needed anyway.  */
467   if (tf->isref ())
468     return false;
469 
470   Type *tn = tf->next->toBasetype ();
471 
472   return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
473 }
474 
475 /* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by
476    Target::getTargetInfo().  */
477 
478 void
d_add_target_info_handlers(const d_target_info_spec * handlers)479 d_add_target_info_handlers (const d_target_info_spec *handlers)
480 {
481   gcc_assert (handlers != NULL);
482 
483   if (d_target_info_table.is_empty ())
484     d_target_info_table.create (8);
485 
486   for (size_t i = 0; handlers[i].name != NULL; i++)
487     d_target_info_table.safe_push (handlers[i]);
488 }
489 
490 /* Handle a call to `__traits(getTargetInfo, "cppStd")'.  */
491 
492 tree
d_handle_target_cpp_std(void)493 d_handle_target_cpp_std (void)
494 {
495   return build_integer_cst (global.params.cplusplus);
496 }
497 
498 /* Handle a call to `__traits(getTargetInfo, "cppRuntimeLibrary")'.  */
499 
500 tree
d_handle_target_cpp_runtime_library(void)501 d_handle_target_cpp_runtime_library (void)
502 {
503   /* The driver only ever optionally links to libstdc++.  */
504   const char *libstdcxx = "libstdc++";
505   return build_string_literal (strlen (libstdcxx) + 1, libstdcxx);
506 }
507 
508 /* Handle a call to `__traits(getTargetInfo, "objectFormat")'.  */
509 
510 tree
d_handle_target_object_format(void)511 d_handle_target_object_format (void)
512 {
513   const char *objfmt;
514 
515 #ifdef OBJECT_FORMAT_ELF
516   objfmt = "elf";
517 #else
518   if (TARGET_COFF || TARGET_PECOFF)
519     objfmt = "coff";
520   else
521     objfmt = "";
522 #endif
523 
524   return build_string_literal (strlen (objfmt) + 1, objfmt);
525 }
526 
527 /* Look up the target info KEY in the available getTargetInfo tables, and return
528    the result as an Expression, or NULL if KEY is not found.  When the key must
529    always exist, but is not supported, an empty string expression is returned.
530    LOC is the location to use for the returned expression.  */
531 
532 Expression *
getTargetInfo(const char * key,const Loc & loc)533 Target::getTargetInfo (const char *key, const Loc &loc)
534 {
535   unsigned ix;
536   d_target_info_spec *spec;
537 
538   FOR_EACH_VEC_ELT (d_target_info_table, ix, spec)
539     {
540       tree result;
541 
542       if (strcmp (key, spec->name) != 0)
543 	continue;
544 
545       /* Get the requested information, or empty string if unhandled.  */
546       if (spec->handler)
547 	{
548 	  result = (spec->handler) ();
549 	  /* Handler didn't return a result, meaning it really does not support
550 	     the key in the current target configuration.  Check whether there
551 	     are any other handlers which may recognize the key.  */
552 	  if (result == NULL_TREE)
553 	    continue;
554 	}
555       else
556 	result = build_string_literal (1, "");
557 
558       gcc_assert (result);
559       return d_eval_constant_expression (loc, result);
560     }
561 
562   return NULL;
563 }
564 
565 /* Returns true if the callee invokes destructors for arguments.  */
566 
567 bool
isCalleeDestroyingArgs(TypeFunction * tf)568 Target::isCalleeDestroyingArgs (TypeFunction *tf)
569 {
570   return tf->linkage == LINK::d;
571 }
572 
573 /* Returns true if the implementation for object monitors is always defined
574    in the D runtime library (rt/monitor_.d).  */
575 
576 bool
libraryObjectMonitors(FuncDeclaration *,Statement *)577 Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
578 {
579   return true;
580 }
581 
582 /* Decides whether an `in' parameter of the specified POD type PARAM_TYPE is to
583    be passed by reference or by valie.  This is used only when compiling with
584    `-fpreview=in' enabled.  */
585 
586 bool
preferPassByRef(Type * param_type)587 Target::preferPassByRef (Type *param_type)
588 {
589   if (param_type->size () == SIZE_INVALID)
590     return false;
591 
592   tree type = build_ctype (param_type);
593 
594   /* Prefer a `ref' if the type is an aggregate, and its size is greater than
595      its alignment.  */
596   if (AGGREGATE_TYPE_P (type)
597       && (!valid_constant_size_p (TYPE_SIZE_UNIT (type))
598 	  || compare_tree_int (TYPE_SIZE_UNIT (type), TYPE_ALIGN (type)) > 0))
599     return true;
600 
601   /* If the back-end is always going to pass this by invisible reference.  */
602   if (pass_by_reference (NULL, function_arg_info (type, true)))
603     return true;
604 
605   /* If returning the parameter means the caller will do RVO.  */
606   if (targetm.calls.return_in_memory (type, NULL_TREE))
607     return true;
608 
609   return false;
610 }
611