@@ -1,3 +1,51 @@
+2014-02-13 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_get_builtin_function): New.
+ * libgccjit.map (gcc_jit_context_get_builtin_function): New.
+ * libgccjit++.h (gccjit::context::get_builtin_function): New method.
+
+ * Make-lang.in (jit_OBJS): Add jit/jit-builtins.o
+ * jit-builtins.c: New source file, for managing builtin functions
+ and their types.
+ * jit-builtins.h: Likewise.
+
+ * libgccjit.c (gcc_jit_context_new_function): Pass BUILT_IN_NONE for
+ the new argument of new_function
+ (gcc_jit_context_get_builtin_function): New.
+
+ * internal-api.h: Add idempotency guards.
+ (gcc::jit::recording::context::new_function): Add parameter
+ for builtin functions.
+ (gcc::jit::recording::context::get_builtin_function): New method.
+ (gcc::jit::recording::context::m_builtins_manager): New field.
+ (gcc::jit::recording::type::as_a_function_type): New virtual function.
+ (gcc::jit::recording::function_type): New subclass of type.
+ (gcc::jit::recording::function::function): Add parameter for
+ builtin functions.
+ (gcc::jit::recording::function::m_builtin_id): New field.
+ (gcc::jit::recording::function::new_function_type): New method.
+ (gcc::jit::playback::function::function): Add parameter for
+ builtin functions.
+ * internal-api.c (gcc::jit::recording::context::context):
+ NULL-initialize new field m_builtins_manager.
+ (gcc::jit::recording::context::~context): Clean up the builtins
+ manager, if one has been created.
+ (gcc::jit::recording::context::new_function): Add parameter
+ (gcc::jit::recording::context::get_builtin_function): New method.
+ (gcc::jit::recording::function_type::function_type): Implement
+ constructor for new subclass.
+ (gcc::jit::recording::function_type::dereference): Implement
+ method for new subclass.
+ (gcc::jit::recording::function_type::replay_into): Likewise.
+ (gcc::jit::recording::function_type::make_debug_string): Likewise.
+ (gcc::jit::recording::function::function): Add parameter for
+ builtin functions.
+ (gcc::jit::recording::function::replay_into): Likewise for
+ creation of playback object.
+ (gcc::jit::recording::function::new_function_type): New method.
+ (gcc::jit::playback::function::new_function): Add parameter for
+ builtin functions, using it to set up the fndecl accordingly.
+
2014-02-11 David Malcolm <dmalcolm@redhat.com>
* libgccjit.c (IS_ASCII_ALPHA): New macro.
@@ -45,7 +45,8 @@ jit: libgccjit.so
# Tell GNU make to ignore these if they exist.
.PHONY: jit
-jit_OBJS = attribs.o jit/dummy-frontend.o jit/libgccjit.o jit/internal-api.o
+jit_OBJS = attribs.o jit/dummy-frontend.o jit/libgccjit.o jit/internal-api.o \
+ jit/jit-builtins.o
# Use strict warnings for this front end.
jit-warn = $(STRICT_WARN)
@@ -20,6 +20,7 @@
#include <pthread.h>
#include "internal-api.h"
+#include "jit-builtins.h"
namespace gcc {
namespace jit {
@@ -61,7 +62,8 @@ recording::context::context (context *parent_ctxt)
: m_parent_ctxt (parent_ctxt),
m_error_count (0),
m_mementos (),
- m_FILE_type (NULL)
+ m_FILE_type (NULL),
+ m_builtins_manager(NULL)
{
m_first_error_str[0] = '\0';
@@ -97,6 +99,9 @@ recording::context::~context ()
{
delete m;
}
+
+ if (m_builtins_manager)
+ delete m_builtins_manager;
}
void
@@ -307,17 +312,27 @@ recording::context::new_function (recording::location *loc,
const char *name,
int num_params,
recording::param **params,
- int is_variadic)
+ int is_variadic,
+ enum built_in_function builtin_id)
{
recording::function *result =
new recording::function (this,
loc, kind, return_type,
new_string (name),
- num_params, params, is_variadic);
+ num_params, params, is_variadic,
+ builtin_id);
record (result);
return result;
}
+recording::function *
+recording::context::get_builtin_function (const char *name)
+{
+ if (!m_builtins_manager)
+ m_builtins_manager = new builtins_manager (this);
+ return m_builtins_manager->get_builtin_function (name);
+}
+
recording::lvalue *
recording::context::new_global (recording::location *loc,
recording::type *type,
@@ -797,6 +812,94 @@ recording::array_type::make_debug_string ()
m_num_elements);
}
+/* gcc::jit::recording::function_type */
+recording::function_type::function_type (context *ctxt,
+ type *return_type,
+ int num_params,
+ type **param_types,
+ int is_variadic)
+: type (ctxt),
+ m_return_type (return_type),
+ m_param_types (),
+ m_is_variadic (is_variadic)
+{
+ for (int i = 0; i< num_params; i++)
+ m_param_types.safe_push (param_types[i]);
+}
+
+recording::type *
+recording::function_type::dereference ()
+{
+ return NULL;
+}
+
+void
+recording::function_type::replay_into (replayer *r)
+{
+ /* Convert m_param_types to a vec of playback type. */
+ vec <playback::type *> param_types;
+ int i;
+ recording::type *type;
+ param_types.create (m_param_types.length ());
+ FOR_EACH_VEC_ELT (m_param_types, i, type)
+ param_types.safe_push (type->playback_type ());
+
+ set_playback_obj (r->new_function_type (m_return_type->playback_type (),
+ ¶m_types,
+ m_is_variadic));
+}
+
+recording::string *
+recording::function_type::make_debug_string ()
+{
+ /* First, build a buffer for the arguments. */
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< m_param_types.length (); i++)
+ {
+ sz += strlen (m_param_types[i]->get_debug_string ());
+ sz += 2; /* ", " separator */
+ }
+ if (m_is_variadic)
+ sz += 5; /* ", ..." separator and ellipsis */
+
+ /* Now allocate and populate the buffer. */
+ char *argbuf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< m_param_types.length (); i++)
+ {
+ strcpy (argbuf + len, m_param_types[i]->get_debug_string ());
+ len += strlen (m_param_types[i]->get_debug_string ());
+ if (i + 1 < m_param_types.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ }
+ if (m_is_variadic)
+ {
+ if (m_param_types.length ())
+ {
+ strcpy (argbuf + len, ", ");
+ len += 2;
+ }
+ strcpy (argbuf + len, "...");
+ len += 3;
+ }
+ argbuf[len] = '\0';
+
+ /* ...and use it to get the string for the call as a whole. */
+ string *result = string::from_printf (m_ctxt,
+ "%s (%s)",
+ m_return_type->get_debug_string (),
+ argbuf);
+
+ delete[] argbuf;
+
+ return result;
+}
+
/* gcc::jit::recording::field:: */
void
recording::field::replay_into (replayer *r)
@@ -928,14 +1031,16 @@ recording::function::function (context *ctxt,
recording::string *name,
int num_params,
recording::param **params,
- int is_variadic)
+ int is_variadic,
+ enum built_in_function builtin_id)
: memento (ctxt),
m_loc (loc),
m_kind (kind),
m_return_type (return_type),
m_name (name),
m_params (),
- m_is_variadic (is_variadic)
+ m_is_variadic (is_variadic),
+ m_builtin_id (builtin_id)
{
for (int i = 0; i< num_params; i++)
m_params.safe_push (params[i]);
@@ -957,7 +1062,8 @@ recording::function::replay_into (replayer *r)
m_return_type->playback_type (),
m_name->c_str (),
¶ms,
- m_is_variadic));
+ m_is_variadic,
+ m_builtin_id));
}
recording::lvalue *
@@ -1864,6 +1970,34 @@ new_struct_type (location *loc,
return new type (t);
}
+playback::type *
+playback::context::
+new_function_type (type *return_type,
+ vec<type *> *param_types,
+ int is_variadic)
+{
+ int i;
+ type *param_type;
+
+ tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
+
+ FOR_EACH_VEC_ELT (*param_types, i, param_type)
+ arg_types[i] = param_type->as_tree ();
+
+ tree fn_type;
+ if (is_variadic)
+ fn_type =
+ build_varargs_function_type_array (return_type->as_tree (),
+ param_types->length (),
+ arg_types);
+ else
+ fn_type = build_function_type_array (return_type->as_tree (),
+ param_types->length (),
+ arg_types);
+ free (arg_types);
+
+ return new type (fn_type);
+}
playback::param *
playback::context::
@@ -1888,7 +2022,8 @@ new_function (location *loc,
type *return_type,
const char *name,
vec<param *> *params,
- int is_variadic)
+ int is_variadic,
+ enum built_in_function builtin_id)
{
int i;
param *param;
@@ -1921,6 +2056,14 @@ new_function (location *loc,
DECL_IGNORED_P (resdecl) = 1;
DECL_RESULT (fndecl) = resdecl;
+ if (builtin_id)
+ {
+ DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
+ DECL_FUNCTION_CODE (fndecl) = builtin_id;
+ gcc_assert (loc == NULL);
+ DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
+ }
+
if (kind != GCC_JIT_FUNCTION_IMPORTED)
{
tree param_decl_list = NULL;
@@ -1,3 +1,6 @@
+#ifndef INTERNAL_API_H
+#define INTERNAL_API_H
+
#include "libgccjit.h"
#include "tree.h"
@@ -74,10 +77,12 @@ class result;
namespace recording {
class context;
+ class builtins_manager; // declared within jit-builtins.h
class memento;
class string;
class location;
class type;
+ class function_type;
class field;
class struct_;
class function;
@@ -174,7 +179,11 @@ public:
const char *name,
int num_params,
param **params,
- int is_variadic);
+ int is_variadic,
+ enum built_in_function builtin_id);
+
+ function *
+ get_builtin_function (const char *name);
lvalue *
new_global (location *loc,
@@ -289,6 +298,8 @@ private:
type *m_basic_types[NUM_GCC_JIT_TYPES];
type *m_FILE_type;
+
+ builtins_manager *m_builtins_manager; // lazily created
};
@@ -400,6 +411,9 @@ public:
The caller is responsible for setting an error. */
virtual type *dereference () = 0;
+ /* Dynamic cast. */
+ virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
+
/* Is it typesafe to copy to this type from rtype? */
virtual bool accepts_writes_from (type *rtype)
{
@@ -537,6 +551,32 @@ class array_type : public type
int m_num_elements;
};
+class function_type : public type
+{
+public:
+ function_type (context *ctxt,
+ type *return_type,
+ int num_params,
+ type **param_types,
+ int is_variadic);
+
+ type *dereference ();
+ function_type *as_a_function_type () { return this; }
+ void replay_into (replayer *);
+
+ type * get_return_type () const { return m_return_type; }
+ vec<type *> get_param_types () const { return m_param_types; }
+ int is_variadic () const { return m_is_variadic; }
+
+ private:
+ string * make_debug_string ();
+
+private:
+ type *m_return_type;
+ vec<type *> m_param_types;
+ int m_is_variadic;
+};
+
class field : public memento
{
public:
@@ -695,7 +735,8 @@ public:
string *name,
int num_params,
param **params,
- int is_variadic);
+ int is_variadic,
+ enum built_in_function builtin_id);
void replay_into (replayer *r);
@@ -776,6 +817,7 @@ private:
string *m_name;
vec<param *> m_params;
int m_is_variadic;
+ enum built_in_function m_builtin_id;
};
class label : public memento
@@ -1444,6 +1486,11 @@ public:
const char *name,
vec<field *> *fields);
+ type *
+ new_function_type (type *return_type,
+ vec<type *> *param_types,
+ int is_variadic);
+
param *
new_param (location *loc,
type *type,
@@ -1455,7 +1502,8 @@ public:
type *return_type,
const char *name,
vec<param *> *params,
- int is_variadic);
+ int is_variadic,
+ enum built_in_function builtin_id);
lvalue *
new_global (location *loc,
@@ -1895,3 +1943,4 @@ extern playback::context *active_playback_ctxt;
} // namespace gcc
+#endif /* INTERNAL_API_H */
new file mode 100644
@@ -0,0 +1,395 @@
+/* jit-builtins.c -- Handling of builtin functions during JIT-compilation.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+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 "ansidecl.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "target.h"
+
+#include "internal-api.h"
+#include "jit-builtins.h"
+
+namespace gcc {
+
+namespace jit {
+
+namespace recording {
+
+const char *const prefix = "__builtin_";
+const size_t prefix_len = strlen (prefix);
+
+/* Create "builtin_data", a const table of the data within builtins.def. */
+struct builtin_data
+{
+ const char *name;
+ enum jit_builtin_type type;
+ bool both_p;
+ bool fallback_p;
+
+ const char *get_asm_name () const
+ {
+ if (both_p && fallback_p)
+ return name + prefix_len;
+ else
+ return name;
+ }
+};
+
+#define DEF_BUILTIN(X, NAME, C, TYPE, LT, BOTH_P, FALLBACK_P, NA, AT, IM, COND)\
+ {NAME, TYPE, BOTH_P, FALLBACK_P},
+static const struct builtin_data builtin_data[] =
+{
+#include "builtins.def"
+};
+#undef DEF_BUILTIN
+
+static bool
+matches_builtin (const char *in_name,
+ const struct builtin_data& bd)
+{
+ const bool debug = 0;
+ gcc_assert (bd.name);
+
+ if (debug)
+ fprintf (stderr, "seen builtin: %s\n", bd.name);
+
+ if (0 == strcmp (bd.name, in_name))
+ {
+ return true;
+ }
+
+ if (bd.both_p)
+ {
+ /* Then the macros in builtins.def gave a "__builtin_"
+ prefix to bd.name, but we should also recognize the form
+ without the prefix. */
+ gcc_assert (0 == strncmp (bd.name, prefix, prefix_len));
+ if (debug)
+ fprintf (stderr, "testing without prefix as: %s\n",
+ bd.name + prefix_len);
+ if (0 == strcmp (bd.name + prefix_len, in_name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+find_builtin_by_name (const char *in_name,
+ enum built_in_function *out_id)
+{
+ /* Locate builtin. This currently works by performing repeated
+ strcmp against every possible candidate, which is likely to
+ inefficient.
+
+ We start at index 1 to skip the initial entry (BUILT_IN_NONE), which
+ has a NULL name. */
+ for (unsigned int i = 1;
+ i < sizeof (builtin_data) / sizeof (builtin_data[0]);
+ i++)
+ {
+ const struct builtin_data& bd = builtin_data[i];
+ if (matches_builtin (in_name, bd))
+ {
+ /* Found a match. */
+ *out_id = static_cast<enum built_in_function> (i);
+ return true;
+ }
+ }
+
+ /* Not found. */
+ return false;
+}
+
+// class builtins_manager
+
+builtins_manager::builtins_manager (context *ctxt)
+ : m_ctxt (ctxt)
+{
+ memset (m_types, 0, sizeof (m_types));
+ memset (m_builtin_functions, 0, sizeof (m_builtin_functions));
+}
+
+function *
+builtins_manager::get_builtin_function (const char *name)
+{
+ enum built_in_function builtin_id;
+ if (!find_builtin_by_name (name, &builtin_id))
+ {
+ m_ctxt->add_error ("builtin \"%s\" not found", name);
+ return NULL;
+ }
+
+ gcc_assert (builtin_id >= 0);
+ gcc_assert (builtin_id < END_BUILTINS);
+
+ /* Lazily build the functions, caching them so that repeated calls for
+ the same id on a context give back the same object. */
+ if (!m_builtin_functions[builtin_id])
+ {
+ m_builtin_functions[builtin_id] = make_builtin_function (builtin_id);
+ m_ctxt->record (m_builtin_functions[builtin_id]);
+ }
+
+ return m_builtin_functions[builtin_id];
+}
+
+function *
+builtins_manager::make_builtin_function (enum built_in_function builtin_id)
+{
+ const struct builtin_data& bd = builtin_data[builtin_id];
+ enum jit_builtin_type type_id = bd.type;
+ function_type *func_type = get_type (type_id)->as_a_function_type ();
+ if (!func_type)
+ return NULL;
+
+ vec<type *> param_types = func_type->get_param_types ();
+ recording::param **params = new recording::param *[param_types.length ()];
+
+ int i;
+ type *param_type;
+ FOR_EACH_VEC_ELT (param_types, i, param_type)
+ {
+ char buf[16];
+ snprintf (buf, 16, "arg%d", i);
+ params[i] = m_ctxt->new_param (NULL,
+ param_type,
+ buf);
+ }
+ const char *asm_name = bd.get_asm_name ();
+ function *result =
+ new function (m_ctxt,
+ NULL,
+ GCC_JIT_FUNCTION_IMPORTED, // FIXME
+ func_type->get_return_type (),
+ m_ctxt->new_string (asm_name),
+ param_types.length (),
+ params,
+ func_type->is_variadic (),
+ builtin_id);
+ delete[] params;
+ return result;
+}
+
+type *
+builtins_manager::get_type (enum jit_builtin_type type_id)
+{
+ if (!m_types[type_id])
+ m_types[type_id] = make_type (type_id);
+ return m_types[type_id];
+}
+
+type *
+builtins_manager::make_type (enum jit_builtin_type type_id)
+{
+ /* Use builtin-types.def to construct a switch statement, with each
+ case deferring to one of the methods below:
+ - DEF_PRIMITIVE_TYPE is handled as a call to make_primitive_type.
+ - the various DEF_FUNCTION_TYPE_n are handled by variadic calls
+ to make_fn_type.
+ - similarly for DEF_FUNCTION_TYPE_VAR_n, but setting the
+ "is_variadic" argument.
+ - DEF_POINTER_TYPE is handled by make_ptr_type.
+ That should handle everything, but just in case we also suppy a
+ gcc_unreachable default clause. */
+ switch (type_id)
+ {
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+ case ENUM: return make_primitive_type (ENUM);
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 0);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 1, ARG1);
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8);
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 1, 0);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 1, 1, ARG1);
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ case ENUM: return make_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_POINTER_TYPE(ENUM, TYPE) \
+ case ENUM: return make_ptr_type (ENUM, TYPE);
+
+#include "builtin-types.def"
+
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_POINTER_TYPE
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+type*
+builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
+{
+ switch (type_id)
+ {
+ default:
+ // only some of these types are implemented so far:
+ m_ctxt->add_error ("unimplemented primitive type for builtin: %d", type_id);
+ return NULL;
+
+ case BT_VOID: return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+ case BT_BOOL: return m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
+ case BT_INT: return m_ctxt->get_type (GCC_JIT_TYPE_INT);
+ case BT_UINT: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_INT);
+ case BT_LONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG);
+ case BT_ULONG: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG);
+ case BT_LONGLONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_LONG);
+ case BT_ULONGLONG:
+ return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+ // case BT_INT128:
+ // case BT_UINT128:
+ // case BT_INTMAX:
+ // case BT_UINTMAX:
+ case BT_UINT16: return m_ctxt->get_int_type (2, false);
+ case BT_UINT32: return m_ctxt->get_int_type (4, false);
+ case BT_UINT64: return m_ctxt->get_int_type (8, false);
+ // case BT_WORD:
+ // case BT_UNWINDWORD:
+ case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT);
+ case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE);
+ case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE);
+ // case BT_COMPLEX_FLOAT:
+ // case BT_COMPLEX_DOUBLE:
+ // case BT_COMPLEX_LONGDOUBLE:
+ case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
+ case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR);
+ // case BT_CONST:
+ // case BT_VOLATILE_PTR:
+ // case BT_CONST_VOLATILE_PTR:
+ // case BT_PTRMODE:
+ // case BT_INT_PTR:
+ // case BT_FLOAT_PTR:
+ // case BT_DOUBLE_PTR:
+ // case BT_CONST_DOUBLE_PTR:
+ // case BT_LONGDOUBLE_PTR:
+ // case BT_PID:
+ // case BT_SIZE:
+ // case BT_SSIZE:
+ // case BT_WINT:
+ // case BT_STRING:
+ case BT_CONST_STRING: return m_ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
+ // case BT_DFLOAT32:
+ // case BT_DFLOAT64:
+ // case BT_DFLOAT128:
+ // case BT_DFLOAT32_PTR:
+ // case BT_DFLOAT64_PTR:
+ // case BT_DFLOAT128_PTR:
+ // case BT_VALIST_REF:
+ // case BT_VALIST_ARG:
+ // case BT_I1:
+ // case BT_I2:
+ // case BT_I4:
+ // case BT_I8:
+ // case BT_I16:
+ }
+}
+
+
+function_type *
+builtins_manager::make_fn_type (enum jit_builtin_type,
+ enum jit_builtin_type return_type_id,
+ bool is_variadic,
+ int num_args, ...)
+{
+ va_list list;
+ int i;
+ type **param_types = new type *[num_args];
+ type *return_type = NULL;
+ function_type *result = NULL;
+
+ va_start (list, num_args);
+ for (i = 0; i < num_args; ++i)
+ {
+ enum jit_builtin_type arg_type_id =
+ (enum jit_builtin_type) va_arg (list, int);
+ param_types[i] = get_type (arg_type_id);
+ if (!param_types[i])
+ goto error;
+ }
+ va_end (list);
+
+ return_type = get_type (return_type_id);
+ if (!return_type)
+ goto error;
+
+ result = new function_type (m_ctxt,
+ return_type,
+ num_args,
+ param_types,
+ is_variadic);
+
+ error:
+ delete[] param_types;
+ return result;
+}
+
+type *
+builtins_manager::make_ptr_type (enum jit_builtin_type,
+ enum jit_builtin_type other_type_id)
+{
+ type *base_type = get_type (other_type_id);
+ return base_type->get_pointer ();
+}
+
+} // namespace recording
+} // namespace jit
+} // namespace gcc
new file mode 100644
@@ -0,0 +1,114 @@
+/* jit-builtins.h -- Handling of builtin functions during JIT-compilation.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+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/>. */
+
+#ifndef JIT_BUILTINS_H
+#define JIT_BUILTINS_H
+
+#include "internal-api.h"
+
+namespace gcc {
+
+namespace jit {
+
+namespace recording {
+
+/* Create an enum of the builtin types. */
+
+enum jit_builtin_type
+{
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
+ NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_POINTER_TYPE
+ BT_LAST
+}; /* enum jit_builtin_type */
+
+/***********************************************************************/
+
+class builtins_manager
+{
+public:
+ builtins_manager (context *ctxt);
+
+ function *
+ get_builtin_function (const char *name);
+
+private:
+ function *make_builtin_function (enum built_in_function builtin_id);
+
+ type *get_type (enum jit_builtin_type type_id);
+
+ type *make_type (enum jit_builtin_type type_id);
+
+ type*
+ make_primitive_type (enum jit_builtin_type type_id);
+
+ function_type*
+ make_fn_type (enum jit_builtin_type type_id,
+ enum jit_builtin_type return_type_id,
+ bool is_variadic,
+ int num_args, ...);
+
+ type*
+ make_ptr_type (enum jit_builtin_type type_id,
+ enum jit_builtin_type other_type_id);
+
+private:
+ context *m_ctxt;
+ type *m_types[BT_LAST];
+ function *m_builtin_functions[END_BUILTINS];
+};
+
+} // namespace recording
+} // namespace jit
+} // namespace gcc
+
+#endif /* JIT_BUILTINS_H */
@@ -112,6 +112,8 @@ namespace gccjit
int is_variadic,
location loc = location ());
+ function get_builtin_function (const std::string &name);
+
rvalue new_rvalue (type numeric_type,
int value);
rvalue zero (type numeric_type);
@@ -563,6 +565,13 @@ context::new_function (enum gcc_jit_function_kind kind,
is_variadic));
}
+inline function
+context::get_builtin_function (const std::string &name)
+{
+ return function (gcc_jit_context_get_builtin_function (m_inner_ctxt,
+ name.c_str ()));
+}
+
inline rvalue
context::new_rvalue (type numeric_type,
int value)
@@ -441,7 +441,18 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
ctxt->new_function (loc, kind, return_type, name,
num_params,
(gcc::jit::recording::param **)params,
- is_variadic);
+ is_variadic,
+ BUILT_IN_NONE);
+}
+
+gcc_jit_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+ const char *name)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
+ RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+
+ return static_cast <gcc_jit_function *> (ctxt->get_builtin_function (name));
}
gcc_jit_object *
@@ -439,6 +439,10 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
gcc_jit_param **params,
int is_variadic);
+extern gcc_jit_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+ const char *name);
+
/* Upcasting from function to object. */
extern gcc_jit_object *
gcc_jit_function_as_object (gcc_jit_function *func);
@@ -4,6 +4,7 @@
# Keep this list sorted alphabetically:
gcc_jit_context_acquire;
gcc_jit_context_compile;
+ gcc_jit_context_get_builtin_function;
gcc_jit_context_get_first_error;
gcc_jit_context_get_type;
gcc_jit_context_get_int_type;
@@ -1,3 +1,12 @@
+2014-02-13 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (CHECK_DOUBLE_VALUE): New macro.
+ (CHECK): New macro.
+ * jit.dg/test-functions.c: New testcase, exercising
+ gcc_jit_context_get_builtin_function.
+ * jit.dg/test-combination.c: Add test-functions.c to the combined
+ test.
+
2014-02-11 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-types.c: Add test coverage for getting type
@@ -47,9 +47,38 @@ static char test[1024];
} \
} while (0)
+#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
+ do { \
+ double expected = (EXPECTED); \
+ double actual = (ACTUAL); \
+ if (abs (actual - expected) < 0.00001) \
+ { \
+ pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+ } \
+ else \
+ { \
+ fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+ fprintf (stderr, "incorrect value: %f\n", actual); \
+ abort (); \
+ } \
+ } while (0)
+
#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
check_string_value ((ACTUAL), (EXPECTED));
+#define CHECK(COND) \
+ do { \
+ if (COND) \
+ { \
+ pass ("%s: %s", test, #COND); \
+ } \
+ else \
+ { \
+ fail ("%s: %s", test, #COND); \
+ abort (); \
+ } \
+ } while (0)
+
/* Hooks that testcases should provide. */
extern void
create_code (gcc_jit_context *ctxt, void * user_data);
@@ -52,6 +52,13 @@
#undef create_code
#undef verify_code
+/* test-functions.c */
+#define create_code create_code_functions
+#define verify_code verify_code_functions
+#include "test-functions.c"
+#undef create_code
+#undef verify_code
+
/* test-hello-world.c */
#define create_code create_code_hello_world
#define verify_code verify_code_hello_world
@@ -118,6 +125,7 @@ create_code (gcc_jit_context *ctxt, void * user_data)
create_code_expressions (ctxt, user_data);
create_code_factorial (ctxt, user_data);
create_code_fibonacci (ctxt, user_data);
+ create_code_functions (ctxt, user_data);
create_code_hello_world (ctxt, user_data);
create_code_string_literal (ctxt, user_data);
create_code_sum_of_squares (ctxt, user_data);
@@ -134,6 +142,7 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
verify_code_expressions (ctxt, result);
verify_code_factorial (ctxt, result);
verify_code_fibonacci (ctxt, result);
+ verify_code_functions (ctxt, result);
verify_code_hello_world (ctxt, result);
verify_code_string_literal (ctxt, result);
verify_code_sum_of_squares (ctxt, result);
new file mode 100644
@@ -0,0 +1,175 @@
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+static void
+create_test_of_builtin_strcmp (gcc_jit_context *ctxt)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_of_builtin_strcmp (const char *a, const char *b)
+ {
+ return __builtin_strcmp (a, b);
+ }
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+
+ /* Get the built-in function. */
+ gcc_jit_function *builtin_fn =
+ gcc_jit_context_get_builtin_function (ctxt, "strcmp");
+
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_function_as_object (builtin_fn)),
+ "strcmp");
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "b");
+ gcc_jit_param *params[2] = {param_a, param_b};
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_of_builtin_strcmp",
+ 2, params,
+ 0);
+ gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_param_as_rvalue (param_b)};
+ gcc_jit_rvalue *call =
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ builtin_fn,
+ 2, args);
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (call)),
+ "strcmp (a, b)");
+
+ gcc_jit_function_add_return (test_fn, NULL, call);
+}
+
+static void
+create_test_of_builtin_trig (gcc_jit_context *ctxt)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_of_builtin_trig (double theta)
+ {
+ return 2 * sin (theta) * cos (theta);
+ }
+ (in theory, optimizable to sin (2 * theta))
+ */
+ gcc_jit_type *double_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+ /* Get the built-in functions. */
+ gcc_jit_function *builtin_sin =
+ gcc_jit_context_get_builtin_function (ctxt, "sin");
+ gcc_jit_function *builtin_cos =
+ gcc_jit_context_get_builtin_function (ctxt, "cos");
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_theta =
+ gcc_jit_context_new_param (ctxt, NULL, double_t, "theta");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ double_t,
+ "test_of_builtin_trig",
+ 1, ¶m_theta,
+ 0);
+ gcc_jit_rvalue *args[1] = {gcc_jit_param_as_rvalue (param_theta)};
+ gcc_jit_rvalue *two =
+ gcc_jit_context_new_rvalue_from_int (ctxt, double_t, 2);
+ gcc_jit_rvalue *ret =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ double_t,
+ two,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ double_t,
+ gcc_jit_context_new_call (ctxt, NULL,
+ builtin_sin,
+ 1, args),
+ gcc_jit_context_new_call (ctxt, NULL,
+ builtin_cos,
+ 1, args)));
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (ret)),
+ "(double)2 * sin (theta) * cos (theta)");
+
+ gcc_jit_function_add_return (test_fn, NULL, ret);
+}
+
+static void
+create_use_of_builtins (gcc_jit_context *ctxt)
+{
+ create_test_of_builtin_strcmp (ctxt);
+ create_test_of_builtin_trig (ctxt);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ create_use_of_builtins (ctxt);
+}
+
+static void
+verify_test_of_builtin_strcmp (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (const char *, const char *);
+ CHECK_NON_NULL (result);
+
+ fn_type test_of_builtin_strcmp =
+ (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_strcmp");
+ CHECK_NON_NULL (test_of_builtin_strcmp);
+
+ /* Verify that it correctly called strcmp. */
+ CHECK_VALUE (test_of_builtin_strcmp ("foo", "foo"), 0);
+ CHECK (test_of_builtin_strcmp ("foo", "bar") > 0);
+ CHECK (test_of_builtin_strcmp ("bar", "foo") < 0);
+}
+
+static void
+verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef double (*fn_type) (double);
+ CHECK_NON_NULL (result);
+
+ fn_type test_of_builtin_trig =
+ (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_trig");
+ CHECK_NON_NULL (test_of_builtin_trig);
+
+ /* Verify that it correctly computes
+ sin (2 * theta)
+ (perhaps calling sin and cos). */
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (0.0 ), 0.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 ), 1.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2 ), 0.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI ), 0.0);
+}
+
+static void
+verify_use_of_builtins (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ verify_test_of_builtin_strcmp (ctxt, result);
+ verify_test_of_builtin_trig (ctxt, result);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ verify_use_of_builtins (ctxt, result);
+}