diff gcc/d/runtime.cc @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/d/runtime.cc	Thu Feb 13 11:34:05 2020 +0900
@@ -0,0 +1,315 @@
+/* runtime.cc -- D runtime functions called by generated code.
+   Copyright (C) 2006-2020 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+
+
+/* During the codegen pass, the compiler may do lowering of expressions to call
+   various runtime library functions.  Most are implemented in the `rt' package.
+   We represent them in the frontend here, however there's no guarantee that
+   the compiler implementation actually matches the actual implementation.  */
+
+enum d_libcall_type
+{
+  LCT_VOID,		    /* void		    */
+  LCT_BYTE,		    /* byte		    */
+  LCT_INT,		    /* int		    */
+  LCT_UINT,		    /* uint		    */
+  LCT_BOOL,		    /* bool		    */
+  LCT_DCHAR,		    /* dchar		    */
+  LCT_VOIDPTR,		    /* void*		    */
+  LCT_STRING,		    /* string		    */
+  LCT_WSTRING,		    /* wstring		    */
+  LCT_DSTRING,		    /* dstring		    */
+  LCT_SIZE_T,		    /* size_t		    */
+  LCT_ASSOCARRAY,	    /* void[void]	    */
+  LCT_ARRAY_VOID,	    /* void[]		    */
+  LCT_ARRAY_SIZE_T,	    /* size_t[]		    */
+  LCT_ARRAY_BYTE,	    /* byte[]		    */
+  LCT_ARRAY_STRING,	    /* string[]		    */
+  LCT_ARRAY_WSTRING,	    /* wstring[]	    */
+  LCT_ARRAY_DSTRING,	    /* dstring[]	    */
+  LCT_ARRAYARRAY_BYTE,	    /* byte[][]		    */
+  LCT_POINTER_ASSOCARRAY,   /* void[void]*	    */
+  LCT_POINTER_VOIDPTR,	    /* void**		    */
+  LCT_ARRAYPTR_VOID,	    /* void[]*		    */
+  LCT_ARRAYPTR_BYTE,	    /* byte[]*		    */
+  LCT_TYPEINFO,		    /* TypeInfo		    */
+  LCT_CLASSINFO,	    /* TypeInfo_Class	    */
+  LCT_OBJECT,		    /* Object		    */
+  LCT_CONST_TYPEINFO,	    /* const(TypeInfo)	    */
+  LCT_CONST_CLASSINFO,	    /* const(ClassInfo)	    */
+  LCT_END
+};
+
+/* An array of all types that are used by the runtime functions we need.  */
+
+static Type *libcall_types[LCT_END];
+
+/* Our internal list of library functions.  */
+
+static tree libcall_decls[LIBCALL_LAST];
+
+
+/* Return the frontend Type that is described by TYPE.  Most are readily cached
+   by the frontend proper, and likewise the use of pointerTo(), constOf(), and
+   arrayOf() will return cached types if they have been requested before.  */
+
+static Type *
+get_libcall_type (d_libcall_type type)
+{
+  if (libcall_types[type])
+    return libcall_types[type];
+
+  switch (type)
+    {
+    case LCT_VOID:
+      libcall_types[type] = Type::tvoid;
+      break;
+
+    case LCT_BYTE:
+      libcall_types[type] = Type::tint8;
+      break;
+
+    case LCT_INT:
+      libcall_types[type] = Type::tint32;
+      break;
+
+    case LCT_UINT:
+      libcall_types[type] = Type::tuns32;
+      break;
+
+    case LCT_BOOL:
+      libcall_types[type] = Type::tbool;
+      break;
+
+    case LCT_DCHAR:
+      libcall_types[type] = Type::tdchar;
+      break;
+
+    case LCT_VOIDPTR:
+      libcall_types[type] = Type::tvoidptr;
+      break;
+
+    case LCT_STRING:
+      libcall_types[type] = Type::tstring;
+      break;
+
+    case LCT_WSTRING:
+      libcall_types[type] = Type::twstring;
+      break;
+
+    case LCT_DSTRING:
+      libcall_types[type] = Type::tdstring;
+      break;
+
+    case LCT_SIZE_T:
+      libcall_types[type] = Type::tsize_t;
+      break;
+
+    case LCT_ASSOCARRAY:
+      libcall_types[type] = TypeAArray::create (Type::tvoid, Type::tvoid);
+      break;
+
+    case LCT_TYPEINFO:
+      libcall_types[type] = Type::dtypeinfo->type;
+      break;
+
+    case LCT_CLASSINFO:
+      libcall_types[type] = Type::typeinfoclass->type;
+      break;
+
+    case LCT_OBJECT:
+      libcall_types[type] = get_object_type ();
+      break;
+
+    case LCT_CONST_TYPEINFO:
+      libcall_types[type] = Type::dtypeinfo->type->constOf ();
+      break;
+
+    case LCT_CONST_CLASSINFO:
+      libcall_types[type] = Type::typeinfoclass->type->constOf ();
+      break;
+
+    case LCT_ARRAY_VOID:
+      libcall_types[type] = Type::tvoid->arrayOf ();
+      break;
+
+    case LCT_ARRAY_SIZE_T:
+      libcall_types[type] = Type::tsize_t->arrayOf ();
+      break;
+
+    case LCT_ARRAY_BYTE:
+      libcall_types[type] = Type::tint8->arrayOf ();
+      break;
+
+    case LCT_ARRAY_STRING:
+      libcall_types[type] = Type::tstring->arrayOf ();
+      break;
+
+    case LCT_ARRAY_WSTRING:
+      libcall_types[type] = Type::twstring->arrayOf ();
+      break;
+
+    case LCT_ARRAY_DSTRING:
+      libcall_types[type] = Type::tdstring->arrayOf ();
+      break;
+
+    case LCT_ARRAYARRAY_BYTE:
+      libcall_types[type] = Type::tint8->arrayOf ()->arrayOf ();
+      break;
+
+    case LCT_POINTER_ASSOCARRAY:
+      libcall_types[type] = get_libcall_type (LCT_ASSOCARRAY)->pointerTo ();
+      break;
+
+    case LCT_POINTER_VOIDPTR:
+      libcall_types[type] = Type::tvoidptr->arrayOf ();
+      break;
+
+    case LCT_ARRAYPTR_VOID:
+      libcall_types[type] = Type::tvoid->arrayOf ()->pointerTo ();
+      break;
+
+    case LCT_ARRAYPTR_BYTE:
+      libcall_types[type] = Type::tint8->arrayOf ()->pointerTo ();
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return libcall_types[type];
+}
+
+/* Builds and returns function declaration named NAME.  The RETURN_TYPE is
+   the type returned, FLAGS are the expression call flags, and NPARAMS is
+   the number of arguments, the types of which are provided in `...'.  */
+
+static tree
+build_libcall_decl (const char *name, d_libcall_type return_type,
+		    int flags, int nparams, ...)
+{
+  tree *args = XALLOCAVEC (tree, nparams);
+  bool varargs = false;
+  tree fntype;
+
+  /* Add parameter types, using 'void' as the last parameter type
+     to mean this function accepts a variable list of arguments.  */
+  va_list ap;
+  va_start (ap, nparams);
+
+  for (int i = 0; i < nparams; i++)
+    {
+      d_libcall_type ptype = (d_libcall_type) va_arg (ap, int);
+      Type *type = get_libcall_type (ptype);
+
+      if (type == Type::tvoid)
+	{
+	  varargs = true;
+	  nparams = i;
+	}
+      else
+	args[i] = build_ctype (type);
+    }
+
+  va_end (ap);
+
+  /* Build the function.  */
+  tree tret = build_ctype (get_libcall_type (return_type));
+  if (varargs)
+    fntype = build_varargs_function_type_array (tret, nparams, args);
+  else
+    fntype = build_function_type_array (tret, nparams, args);
+
+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+			  get_identifier (name), fntype);
+  DECL_EXTERNAL (decl) = 1;
+  TREE_PUBLIC (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+  /* Set any attributes on the function, such as malloc or noreturn.  */
+  set_call_expr_flags (decl, flags);
+
+  return decl;
+}
+
+/* Return or create the runtime library function declaration for LIBCALL.
+   Library functions are generated as needed.  This could probably be changed in
+   the future to be done in the compiler init stage, like GCC builtin trees are,
+   however we depend on run-time initialization of types whose definitions are
+   in the library such as `Object' or `TypeInfo'.  */
+
+static tree
+get_libcall (libcall_fn libcall)
+{
+  if (libcall_decls[libcall])
+    return libcall_decls[libcall];
+
+  switch (libcall)
+    {
+#define DEF_D_RUNTIME(CODE, NAME, TYPE, PARAMS, FLAGS) \
+    case LIBCALL_ ## CODE:	\
+      libcall_decls[libcall] = build_libcall_decl (NAME, TYPE, FLAGS, PARAMS); \
+      break;
+
+#include "runtime.def"
+
+#undef DEF_D_RUNTIME
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return libcall_decls[libcall];
+}
+
+/* Generate a call to LIBCALL, returning the result as TYPE.  NARGS is the
+   number of call arguments, the expressions of which are provided in `...'.
+   This does not perform conversions or promotions on the arguments.  */
+
+tree
+build_libcall (libcall_fn libcall, Type *type, int nargs, ...)
+{
+  /* Build the call expression to the runtime function.  */
+  tree decl = get_libcall (libcall);
+  tree *args = XALLOCAVEC (tree, nargs);
+  va_list ap;
+
+  va_start (ap, nargs);
+  for (int i = 0; i < nargs; i++)
+    args[i] = va_arg (ap, tree);
+  va_end (ap);
+
+  tree result = build_call_expr_loc_array (input_location, decl, nargs, args);
+
+  /* Assumes caller knows what it is doing.  */
+  return convert (build_ctype (type), result);
+}