xref: /netbsd/external/gpl3/gcc/dist/gcc/d/d-target.cc (revision f0fbc68b)
1 /* d-target.cc -- Target interface for the D front end.
2    Copyright (C) 2013-2022 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.boolsize = (BOOL_TYPE_SIZE / BITS_PER_UNIT);
162   this->c.shortsize = (SHORT_TYPE_SIZE / BITS_PER_UNIT);
163   this->c.intsize = (INT_TYPE_SIZE / BITS_PER_UNIT);
164   this->c.longsize = (LONG_TYPE_SIZE / BITS_PER_UNIT);
165   this->c.long_longsize = (LONG_LONG_TYPE_SIZE / BITS_PER_UNIT);
166   this->c.long_doublesize = (LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT);
167   this->c.wchar_tsize = (WCHAR_TYPE_SIZE / BITS_PER_UNIT);
168 
169   this->c.bitFieldStyle = targetm.ms_bitfield_layout_p (unknown_type_node)
170     ? TargetC::BitFieldStyle::MS : TargetC::BitFieldStyle::Gcc_Clang;
171 
172   /* Set-up target C++ ABI.  */
173   this->cpp.reverseOverloads = false;
174   this->cpp.exceptions = true;
175   this->cpp.twoDtorInVtable = true;
176 
177   /* Set-up target Objective-C ABI.  */
178   this->objc.supported = false;
179 
180   /* Set-up environmental settings.  */
181   this->obj_ext = "o";
182   this->lib_ext = "a";
183   this->dll_ext = "so";
184   this->run_noext = true;
185 
186   /* Initialize all compile-time properties for floating-point types.
187      Should ensure that our real_t type is able to represent real_value.  */
188   gcc_assert (sizeof (real_t) >= sizeof (real_value));
189 
190   define_float_constants (this->FloatProperties, float_type_node);
191   define_float_constants (this->DoubleProperties, double_type_node);
192   define_float_constants (this->RealProperties, long_double_type_node);
193 
194   /* Commonly used floating-point constants.  */
195   const machine_mode mode = TYPE_MODE (long_double_type_node);
196   real_convert (&CTFloat::zero.rv (), mode, &dconst0);
197   real_convert (&CTFloat::one.rv (), mode, &dconst1);
198   real_convert (&CTFloat::minusone.rv (), mode, &dconstm1);
199   real_convert (&CTFloat::half.rv (), mode, &dconsthalf);
200 
201   /* Initialize target info tables, the keys required by the language are added
202      last, so that the OS and CPU handlers can override.  */
203   targetdm.d_register_cpu_target_info ();
204   targetdm.d_register_os_target_info ();
205   d_add_target_info_handlers (d_language_target_info);
206 }
207 
208 /* Return GCC memory alignment size for type TYPE.  */
209 
210 unsigned
alignsize(Type * type)211 Target::alignsize (Type *type)
212 {
213   gcc_assert (type->isTypeBasic ());
214   return min_align_of_type (build_ctype (type));
215 }
216 
217 /* Return GCC field alignment size for type TYPE.  */
218 
219 unsigned
fieldalign(Type * type)220 Target::fieldalign (Type *type)
221 {
222   /* Work out the correct alignment for the field decl.  */
223   unsigned int align = type->alignsize () * BITS_PER_UNIT;
224 
225 #ifdef BIGGEST_FIELD_ALIGNMENT
226   align = MIN (align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
227 #endif
228 
229 #ifdef ADJUST_FIELD_ALIGN
230   if (type->isTypeBasic ())
231     align = ADJUST_FIELD_ALIGN (NULL_TREE, build_ctype (type), align);
232 #endif
233 
234   /* Also controlled by -fpack-struct=  */
235   if (maximum_field_alignment)
236     align = MIN (align, maximum_field_alignment);
237 
238   return align / BITS_PER_UNIT;
239 }
240 
241 /* Returns a Type for the va_list type of the target.  */
242 
243 Type *
va_listType(const Loc &,Scope *)244 Target::va_listType (const Loc &, Scope *)
245 {
246   if (this->tvalist)
247     return this->tvalist;
248 
249   /* Build the "standard" abi va_list.  */
250   this->tvalist = build_frontend_type (va_list_type_node);
251   if (!this->tvalist)
252     sorry ("cannot represent built-in %<va_list%> type in D");
253 
254   /* Map the va_list type to the D frontend Type.  This is to prevent both
255      errors in gimplification or an ICE in targetm.canonical_va_list_type.  */
256   this->tvalist->ctype = va_list_type_node;
257   TYPE_LANG_SPECIFIC (va_list_type_node) = build_lang_type (this->tvalist);
258 
259   return this->tvalist;
260 }
261 
262 /* Checks whether the target supports a vector type with total size SZ
263    (in bytes) and element type TYPE.  */
264 
265 int
isVectorTypeSupported(int sz,Type * type)266 Target::isVectorTypeSupported (int sz, Type *type)
267 {
268   /* Size must be greater than zero, and a power of two.  */
269   if (sz <= 0 || sz & (sz - 1))
270     return 3;
271 
272   /* __vector(void[]) is treated same as __vector(ubyte[])  */
273   if (type == Type::tvoid)
274     type = Type::tuns8;
275 
276   /* No support for non-trivial types, complex types, or booleans.  */
277   if (!type->isTypeBasic () || type->iscomplex () || type->ty == TY::Tbool)
278     return 2;
279 
280   /* In [simd/vector extensions], which vector types are supported depends on
281      the target.  The implementation is expected to only support the vector
282      types that are implemented in the target's hardware.  */
283   unsigned HOST_WIDE_INT nunits = sz / type->size ();
284   tree ctype = build_vector_type (build_ctype (type), nunits);
285 
286   if (!targetm.vector_mode_supported_p (TYPE_MODE (ctype)))
287     return 2;
288 
289   return 0;
290 }
291 
292 /* Checks whether the target supports operation OP for vectors of type TYPE.
293    For binary ops T2 is the type of the right-hand operand.
294    Returns true if the operation is supported or type is not a vector.  */
295 
296 bool
isVectorOpSupported(Type * type,EXP op,Type *)297 Target::isVectorOpSupported (Type *type, EXP op, Type *)
298 {
299   if (type->ty != TY::Tvector)
300     return true;
301 
302   /* Don't support if type is non-scalar, such as __vector(void[]).  */
303   if (!type->isscalar ())
304     return false;
305 
306   /* Don't support if expression cannot be represented.  */
307   switch (op)
308     {
309     case EXP::pow:
310     case EXP::powAssign:
311       /* pow() is lowered as a function call.  */
312       return false;
313 
314     case EXP::mod:
315     case EXP::modAssign:
316       /* fmod() is lowered as a function call.  */
317       if (type->isfloating ())
318 	return false;
319       break;
320 
321     case EXP::andAnd:
322     case EXP::orOr:
323       /* Logical operators must have a result type of bool.  */
324       return false;
325 
326     case EXP::lessOrEqual:
327     case EXP::lessThan:
328     case EXP::greaterOrEqual:
329     case EXP::greaterThan:
330     case EXP::equal:
331     case EXP::notEqual:
332     case EXP::identity:
333     case EXP::notIdentity:
334       /* Comparison operators must have a result type of bool.  */
335       return false;
336 
337     default:
338       break;
339     }
340 
341   return true;
342 }
343 
344 /* Return the symbol mangling of S for C++ linkage.  */
345 
346 const char *
toMangle(Dsymbol * s)347 TargetCPP::toMangle (Dsymbol *s)
348 {
349   return toCppMangleItanium (s);
350 }
351 
352 /* Return the symbol mangling of CD for C++ linkage.  */
353 
354 const char *
typeInfoMangle(ClassDeclaration * cd)355 TargetCPP::typeInfoMangle (ClassDeclaration *cd)
356 {
357   return cppTypeInfoMangleItanium (cd);
358 }
359 
360 /* Get mangle name of a this-adjusting thunk to the function declaration FD
361    at call offset OFFSET for C++ linkage.  */
362 
363 const char *
thunkMangle(FuncDeclaration * fd,int offset)364 TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
365 {
366   return cppThunkMangleItanium (fd, offset);
367 }
368 
369 /* For a vendor-specific type, return a string containing the C++ mangling.
370    In all other cases, return NULL.  */
371 
372 const char *
typeMangle(Type * type)373 TargetCPP::typeMangle (Type *type)
374 {
375   if (type->isTypeBasic () || type->ty == TY::Tvector
376       || type->ty == TY::Tstruct)
377     {
378       tree ctype = build_ctype (type);
379       return targetm.mangle_type (ctype);
380     }
381 
382   return NULL;
383 }
384 
385 /* Return the type that will really be used for passing the given parameter
386    ARG to an extern(C++) function.  */
387 
388 Type *
parameterType(Type * type)389 TargetCPP::parameterType (Type *type)
390 {
391   /* Could be a va_list, which we mangle as a pointer.  */
392   Type *tvalist = target.va_listType (Loc (), NULL);
393   if (type->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
394     {
395       Type *tb = type->toBasetype ()->mutableOf ();
396       if (tb == tvalist)
397 	{
398 	  tb = type->nextOf ()->pointerTo ();
399 	  type = tb->castMod (type->mod);
400 	}
401     }
402 
403   return type;
404 }
405 
406 /* Checks whether TYPE is a vendor-specific fundamental type.  Stores the result
407    in IS_FUNDAMENTAL and returns true if the parameter was set.  */
408 
409 bool
fundamentalType(const Type *,bool &)410 TargetCPP::fundamentalType (const Type *, bool &)
411 {
412   return false;
413 }
414 
415 /* Get the starting offset position for fields of an `extern(C++)` class
416    that is derived from the given BASE_CLASS.  */
417 
418 unsigned
derivedClassOffset(ClassDeclaration * base_class)419 TargetCPP::derivedClassOffset(ClassDeclaration *base_class)
420 {
421   return base_class->structsize;
422 }
423 
424 /* Return the default `extern (System)' linkage for the target.  */
425 
426 LINK
systemLinkage(void)427 Target::systemLinkage (void)
428 {
429   unsigned link_system, link_windows;
430 
431   if (targetdm.d_has_stdcall_convention (&link_system, &link_windows))
432     {
433       /* In [attribute/linkage], `System' is the same as `Windows' on Windows
434 	 platforms, and `C' on other platforms.  */
435       if (link_system)
436 	return LINK::windows;
437     }
438 
439   return LINK::c;
440 }
441 
442 /* Generate a TypeTuple of the equivalent types used to determine if a
443    function argument of the given type can be passed in registers.
444    The results of this are highly platform dependent, and intended
445    primarly for use in implementing va_arg() with RTTI.  */
446 
447 TypeTuple *
toArgTypes(Type *)448 Target::toArgTypes (Type *)
449 {
450   /* Not implemented, however this is not currently used anywhere.  */
451   return NULL;
452 }
453 
454 /* Determine return style of function, whether in registers or through a
455    hidden pointer to the caller's stack.  */
456 
457 bool
isReturnOnStack(TypeFunction * tf,bool)458 Target::isReturnOnStack (TypeFunction *tf, bool)
459 {
460   /* Need the back-end type to determine this, but this is called from the
461      frontend before semantic processing is finished.  An accurate value
462      is not currently needed anyway.  */
463   if (tf->isref ())
464     return false;
465 
466   Type *tn = tf->next->toBasetype ();
467   if (tn->size () == SIZE_INVALID)
468     return false;
469 
470   return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
471 }
472 
473 /* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by
474    Target::getTargetInfo().  */
475 
476 void
d_add_target_info_handlers(const d_target_info_spec * handlers)477 d_add_target_info_handlers (const d_target_info_spec *handlers)
478 {
479   gcc_assert (handlers != NULL);
480 
481   if (d_target_info_table.is_empty ())
482     d_target_info_table.create (8);
483 
484   for (size_t i = 0; handlers[i].name != NULL; i++)
485     d_target_info_table.safe_push (handlers[i]);
486 }
487 
488 /* Handle a call to `__traits(getTargetInfo, "cppStd")'.  */
489 
490 tree
d_handle_target_cpp_std(void)491 d_handle_target_cpp_std (void)
492 {
493   return build_integer_cst (global.params.cplusplus);
494 }
495 
496 /* Handle a call to `__traits(getTargetInfo, "cppRuntimeLibrary")'.  */
497 
498 tree
d_handle_target_cpp_runtime_library(void)499 d_handle_target_cpp_runtime_library (void)
500 {
501   /* The driver only ever optionally links to libstdc++.  */
502   const char *libstdcxx = "libstdc++";
503   return build_string_literal (strlen (libstdcxx) + 1, libstdcxx);
504 }
505 
506 /* Handle a call to `__traits(getTargetInfo, "objectFormat")'.  */
507 
508 tree
d_handle_target_object_format(void)509 d_handle_target_object_format (void)
510 {
511   const char *objfmt;
512 
513 #ifdef OBJECT_FORMAT_ELF
514   objfmt = "elf";
515 #else
516   if (TARGET_COFF || TARGET_PECOFF)
517     objfmt = "coff";
518   else
519     objfmt = "";
520 #endif
521 
522   return build_string_literal (strlen (objfmt) + 1, objfmt);
523 }
524 
525 /* Look up the target info KEY in the available getTargetInfo tables, and return
526    the result as an Expression, or NULL if KEY is not found.  When the key must
527    always exist, but is not supported, an empty string expression is returned.
528    LOC is the location to use for the returned expression.  */
529 
530 Expression *
getTargetInfo(const char * key,const Loc & loc)531 Target::getTargetInfo (const char *key, const Loc &loc)
532 {
533   unsigned ix;
534   d_target_info_spec *spec;
535 
536   FOR_EACH_VEC_ELT (d_target_info_table, ix, spec)
537     {
538       tree result;
539 
540       if (strcmp (key, spec->name) != 0)
541 	continue;
542 
543       /* Get the requested information, or empty string if unhandled.  */
544       if (spec->handler)
545 	{
546 	  result = (spec->handler) ();
547 	  /* Handler didn't return a result, meaning it really does not support
548 	     the key in the current target configuration.  Check whether there
549 	     are any other handlers which may recognize the key.  */
550 	  if (result == NULL_TREE)
551 	    continue;
552 	}
553       else
554 	result = build_string_literal (1, "");
555 
556       gcc_assert (result);
557       return d_eval_constant_expression (loc, result);
558     }
559 
560   return NULL;
561 }
562 
563 /* Returns true if the callee invokes destructors for arguments.  */
564 
565 bool
isCalleeDestroyingArgs(TypeFunction * tf)566 Target::isCalleeDestroyingArgs (TypeFunction *tf)
567 {
568   return tf->linkage == LINK::d;
569 }
570 
571 /* Returns true if the implementation for object monitors is always defined
572    in the D runtime library (rt/monitor_.d).  */
573 
574 bool
libraryObjectMonitors(FuncDeclaration *,Statement *)575 Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
576 {
577   return true;
578 }
579 
580 /* Returns true if the target supports `pragma(linkerDirective)'.  */
581 
582 bool
supportsLinkerDirective(void) const583 Target::supportsLinkerDirective (void) const
584 {
585   return false;
586 }
587 
588 /* Decides whether an `in' parameter of the specified POD type PARAM_TYPE is to
589    be passed by reference or by valie.  This is used only when compiling with
590    `-fpreview=in' enabled.  */
591 
592 bool
preferPassByRef(Type * param_type)593 Target::preferPassByRef (Type *param_type)
594 {
595   if (param_type->size () == SIZE_INVALID)
596     return false;
597 
598   tree type = build_ctype (param_type);
599 
600   /* Prefer a `ref' if the type is an aggregate, and its size is greater than
601      its alignment.  */
602   if (AGGREGATE_TYPE_P (type)
603       && (!valid_constant_size_p (TYPE_SIZE_UNIT (type))
604 	  || compare_tree_int (TYPE_SIZE_UNIT (type), TYPE_ALIGN (type)) > 0))
605     return true;
606 
607   /* If the back-end is always going to pass this by invisible reference.  */
608   if (pass_by_reference (NULL, function_arg_info (type, true)))
609     return true;
610 
611   /* If returning the parameter means the caller will do RVO.  */
612   if (targetm.calls.return_in_memory (type, NULL_TREE))
613     return true;
614 
615   return false;
616 }
617