Home | History | Annotate | Line # | Download | only in d
      1 /* runtime.cc -- D runtime functions called by generated code.
      2    Copyright (C) 2006-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/mtype.h"
     24 
     25 #include "tree.h"
     26 #include "fold-const.h"
     27 #include "stringpool.h"
     28 
     29 #include "d-tree.h"
     30 
     31 
     32 /* During the codegen pass, the compiler may do lowering of expressions to call
     33    various runtime library functions.  Most are implemented in the `rt' package.
     34    We represent them in the frontend here, however there's no guarantee that
     35    the compiler implementation actually matches the actual implementation.  */
     36 
     37 enum d_libcall_type
     38 {
     39   LCT_VOID,		    /* void		    */
     40   LCT_BYTE,		    /* byte		    */
     41   LCT_INT,		    /* int		    */
     42   LCT_UINT,		    /* uint		    */
     43   LCT_BOOL,		    /* bool		    */
     44   LCT_DCHAR,		    /* dchar		    */
     45   LCT_VOIDPTR,		    /* void*		    */
     46   LCT_STRING,		    /* string		    */
     47   LCT_WSTRING,		    /* wstring		    */
     48   LCT_DSTRING,		    /* dstring		    */
     49   LCT_SIZE_T,		    /* size_t		    */
     50   LCT_ASSOCARRAY,	    /* void[void]	    */
     51   LCT_ARRAY_VOID,	    /* void[]		    */
     52   LCT_ARRAY_SIZE_T,	    /* size_t[]		    */
     53   LCT_ARRAY_BYTE,	    /* byte[]		    */
     54   LCT_IMMUTABLE_CHARPTR,    /* immutable(char*)	    */
     55   LCT_ARRAY_STRING,	    /* string[]		    */
     56   LCT_ARRAY_WSTRING,	    /* wstring[]	    */
     57   LCT_ARRAY_DSTRING,	    /* dstring[]	    */
     58   LCT_ARRAYARRAY_BYTE,	    /* byte[][]		    */
     59   LCT_POINTER_ASSOCARRAY,   /* void[void]*	    */
     60   LCT_POINTER_VOIDPTR,	    /* void**		    */
     61   LCT_ARRAYPTR_VOID,	    /* void[]*		    */
     62   LCT_ARRAYPTR_BYTE,	    /* byte[]*		    */
     63   LCT_TYPEINFO,		    /* TypeInfo		    */
     64   LCT_CLASSINFO,	    /* TypeInfo_Class	    */
     65   LCT_OBJECT,		    /* Object		    */
     66   LCT_CONST_TYPEINFO,	    /* const(TypeInfo)	    */
     67   LCT_CONST_CLASSINFO,	    /* const(ClassInfo)	    */
     68   LCT_END
     69 };
     70 
     71 /* An array of all types that are used by the runtime functions we need.  */
     72 
     73 static Type *libcall_types[LCT_END];
     74 
     75 /* Our internal list of library functions.  */
     76 
     77 static tree libcall_decls[LIBCALL_LAST];
     78 
     79 
     80 /* Return the frontend Type that is described by TYPE.  Most are readily cached
     81    by the frontend proper, and likewise the use of pointerTo(), constOf(), and
     82    arrayOf() will return cached types if they have been requested before.  */
     83 
     84 static Type *
     85 get_libcall_type (d_libcall_type type)
     86 {
     87   if (libcall_types[type])
     88     return libcall_types[type];
     89 
     90   switch (type)
     91     {
     92     case LCT_VOID:
     93       libcall_types[type] = Type::tvoid;
     94       break;
     95 
     96     case LCT_BYTE:
     97       libcall_types[type] = Type::tint8;
     98       break;
     99 
    100     case LCT_INT:
    101       libcall_types[type] = Type::tint32;
    102       break;
    103 
    104     case LCT_UINT:
    105       libcall_types[type] = Type::tuns32;
    106       break;
    107 
    108     case LCT_BOOL:
    109       libcall_types[type] = Type::tbool;
    110       break;
    111 
    112     case LCT_DCHAR:
    113       libcall_types[type] = Type::tdchar;
    114       break;
    115 
    116     case LCT_VOIDPTR:
    117       libcall_types[type] = Type::tvoidptr;
    118       break;
    119 
    120     case LCT_STRING:
    121       libcall_types[type] = Type::tstring;
    122       break;
    123 
    124     case LCT_WSTRING:
    125       libcall_types[type] = Type::twstring;
    126       break;
    127 
    128     case LCT_DSTRING:
    129       libcall_types[type] = Type::tdstring;
    130       break;
    131 
    132     case LCT_SIZE_T:
    133       libcall_types[type] = Type::tsize_t;
    134       break;
    135 
    136     case LCT_ASSOCARRAY:
    137       libcall_types[type] = TypeAArray::create (Type::tvoid, Type::tvoid);
    138       break;
    139 
    140     case LCT_TYPEINFO:
    141       libcall_types[type] = Type::dtypeinfo->type;
    142       break;
    143 
    144     case LCT_CLASSINFO:
    145       libcall_types[type] = Type::typeinfoclass->type;
    146       break;
    147 
    148     case LCT_OBJECT:
    149       libcall_types[type] = get_object_type ();
    150       break;
    151 
    152     case LCT_CONST_TYPEINFO:
    153       libcall_types[type] = Type::dtypeinfo->type->constOf ();
    154       break;
    155 
    156     case LCT_CONST_CLASSINFO:
    157       libcall_types[type] = Type::typeinfoclass->type->constOf ();
    158       break;
    159 
    160     case LCT_ARRAY_VOID:
    161       libcall_types[type] = Type::tvoid->arrayOf ();
    162       break;
    163 
    164     case LCT_ARRAY_SIZE_T:
    165       libcall_types[type] = Type::tsize_t->arrayOf ();
    166       break;
    167 
    168     case LCT_ARRAY_BYTE:
    169       libcall_types[type] = Type::tint8->arrayOf ();
    170       break;
    171 
    172     case LCT_ARRAY_STRING:
    173       libcall_types[type] = Type::tstring->arrayOf ();
    174       break;
    175 
    176     case LCT_ARRAY_WSTRING:
    177       libcall_types[type] = Type::twstring->arrayOf ();
    178       break;
    179 
    180     case LCT_ARRAY_DSTRING:
    181       libcall_types[type] = Type::tdstring->arrayOf ();
    182       break;
    183 
    184     case LCT_ARRAYARRAY_BYTE:
    185       libcall_types[type] = Type::tint8->arrayOf ()->arrayOf ();
    186       break;
    187 
    188     case LCT_POINTER_ASSOCARRAY:
    189       libcall_types[type] = get_libcall_type (LCT_ASSOCARRAY)->pointerTo ();
    190       break;
    191 
    192     case LCT_POINTER_VOIDPTR:
    193       libcall_types[type] = Type::tvoidptr->arrayOf ();
    194       break;
    195 
    196     case LCT_ARRAYPTR_VOID:
    197       libcall_types[type] = Type::tvoid->arrayOf ()->pointerTo ();
    198       break;
    199 
    200     case LCT_ARRAYPTR_BYTE:
    201       libcall_types[type] = Type::tint8->arrayOf ()->pointerTo ();
    202       break;
    203 
    204     case LCT_IMMUTABLE_CHARPTR:
    205       libcall_types[type] = Type::tchar->pointerTo ()->immutableOf ();
    206       break;
    207 
    208     default:
    209       gcc_unreachable ();
    210     }
    211 
    212   return libcall_types[type];
    213 }
    214 
    215 /* Builds and returns function declaration named NAME.  The RETURN_TYPE is
    216    the type returned, FLAGS are the expression call flags, and NPARAMS is
    217    the number of arguments, the types of which are provided in `...'.  */
    218 
    219 static tree
    220 build_libcall_decl (const char *name, d_libcall_type return_type,
    221 		    int flags, int nparams, ...)
    222 {
    223   tree *args = XALLOCAVEC (tree, nparams);
    224   bool varargs = false;
    225   tree fntype;
    226 
    227   /* Add parameter types, using `void' as the last parameter type
    228      to mean this function accepts a variable list of arguments.  */
    229   va_list ap;
    230   va_start (ap, nparams);
    231 
    232   for (int i = 0; i < nparams; i++)
    233     {
    234       d_libcall_type ptype = (d_libcall_type) va_arg (ap, int);
    235       Type *type = get_libcall_type (ptype);
    236 
    237       if (type == Type::tvoid)
    238 	{
    239 	  varargs = true;
    240 	  nparams = i;
    241 	}
    242       else
    243 	args[i] = build_ctype (type);
    244     }
    245 
    246   va_end (ap);
    247 
    248   /* Build the function.  */
    249   tree tret = build_ctype (get_libcall_type (return_type));
    250   if (varargs)
    251     fntype = build_varargs_function_type_array (tret, nparams, args);
    252   else
    253     fntype = build_function_type_array (tret, nparams, args);
    254 
    255   tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
    256 			  get_identifier (name), fntype);
    257   DECL_EXTERNAL (decl) = 1;
    258   TREE_PUBLIC (decl) = 1;
    259   DECL_ARTIFICIAL (decl) = 1;
    260   DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
    261   DECL_VISIBILITY_SPECIFIED (decl) = 1;
    262 
    263   /* Set any attributes on the function, such as malloc or noreturn.  */
    264   set_call_expr_flags (decl, flags);
    265 
    266   return decl;
    267 }
    268 
    269 /* Return or create the runtime library function declaration for LIBCALL.
    270    Library functions are generated as needed.  This could probably be changed in
    271    the future to be done in the compiler init stage, like GCC builtin trees are,
    272    however we depend on run-time initialization of types whose definitions are
    273    in the library such as `Object' or `TypeInfo'.  */
    274 
    275 static tree
    276 get_libcall (libcall_fn libcall)
    277 {
    278   if (libcall_decls[libcall])
    279     return libcall_decls[libcall];
    280 
    281   switch (libcall)
    282     {
    283 #define DEF_D_RUNTIME(CODE, NAME, TYPE, PARAMS, FLAGS) \
    284     case LIBCALL_ ## CODE:	\
    285       libcall_decls[libcall] = build_libcall_decl (NAME, TYPE, FLAGS, PARAMS); \
    286       break;
    287 
    288 #include "runtime.def"
    289 
    290 #undef DEF_D_RUNTIME
    291 
    292     default:
    293       gcc_unreachable ();
    294     }
    295 
    296   return libcall_decls[libcall];
    297 }
    298 
    299 /* Generate a call to LIBCALL, returning the result as TYPE.  NARGS is the
    300    number of call arguments, the expressions of which are provided in `...'.
    301    This does not perform conversions or promotions on the arguments.  */
    302 
    303 tree
    304 build_libcall (libcall_fn libcall, Type *type, int nargs, ...)
    305 {
    306   /* Build the call expression to the runtime function.  */
    307   tree decl = get_libcall (libcall);
    308   tree *args = XALLOCAVEC (tree, nargs);
    309   va_list ap;
    310 
    311   va_start (ap, nargs);
    312   for (int i = 0; i < nargs; i++)
    313     args[i] = va_arg (ap, tree);
    314   va_end (ap);
    315 
    316   tree result = build_call_expr_loc_array (input_location, decl, nargs, args);
    317 
    318   /* Assumes caller knows what it is doing.  */
    319   return convert (build_ctype (type), result);
    320 }
    321