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