1 /* runtime.cc -- D runtime functions called by generated code. 2 Copyright (C) 2006-2020 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_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 * 84 get_libcall_type (d_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 215 build_libcall_decl (const char *name, d_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 d_libcall_type ptype = (d_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 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 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