Home | History | Annotate | Line # | Download | only in d
      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
     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
    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
    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
    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 *
    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
    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
    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 *
    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 *
    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 *
    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 *
    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 *
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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 *
    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
    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
    575 Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
    576 {
    577   return true;
    578 }
    579 
    580 /* Returns true if the target supports `pragma(linkerDirective)'.  */
    581 
    582 bool
    583 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 value.  This is used only when compiling with
    590    `-fpreview=in' enabled.  */
    591 
    592 bool
    593 Target::preferPassByRef (Type *param_type)
    594 {
    595   /* See note in Target::isReturnOnStack.  */
    596   Type *tb = param_type->toBasetype ();
    597   if (tb->size () == SIZE_INVALID)
    598     return false;
    599 
    600   return (tb->ty == TY::Tstruct || tb->ty == TY::Tsarray);
    601 }
    602