https://gcc.gnu.org/g:87f0136fa46c9b0352aa47f637d2f6678b8beb5b

commit r15-5528-g87f0136fa46c9b0352aa47f637d2f6678b8beb5b
Author: Antoni Boucher <boua...@zoho.com>
Date:   Mon Jan 23 17:21:15 2023 -0500

    libgccjit: Add support for machine-dependent builtins
    
    gcc/jit/ChangeLog:
            PR jit/108762
            * docs/topics/compatibility.rst (LIBGCCJIT_ABI_32): New ABI tag.
            * docs/topics/functions.rst: Add documentation for the function
            gcc_jit_context_get_target_builtin_function.
            * dummy-frontend.cc: Include headers target.h, jit-recording.h,
            print-tree.h, unordered_map and string, new variables 
(target_builtins,
            target_function_types, and target_builtins_ctxt), new function
            (tree_type_to_jit_type).
            * jit-builtins.cc: Specify that the function types are not from
            target builtins.
            * jit-playback.cc: New argument is_target_builtin to new_function.
            * jit-playback.h: New argument is_target_builtin to
            new_function.
            * jit-recording.cc: New argument is_target_builtin to
            new_function_type, function_type constructor and function
            constructor, new function
            (get_target_builtin_function).
            * jit-recording.h: Include headers string and unordered_map, new
            variable target_function_types, new argument is_target_builtin
            to new_function_type, function_type and function, new functions
            (get_target_builtin_function, copy).
            * libgccjit.cc: New function
            (gcc_jit_context_get_target_builtin_function).
            * libgccjit.h: New function
            (gcc_jit_context_get_target_builtin_function).
            * libgccjit.map: New functions
            (gcc_jit_context_get_target_builtin_function).
    
    gcc/testsuite:
            PR jit/108762
            * jit.dg/all-non-failing-tests.h: New test test-target-builtins.c.
            * jit.dg/test-target-builtins.c: New test.

Diff:
---
 gcc/jit/docs/topics/compatibility.rst        |  10 +-
 gcc/jit/docs/topics/functions.rst            |  19 +++
 gcc/jit/dummy-frontend.cc                    | 205 ++++++++++++++++++++++++++-
 gcc/jit/jit-builtins.cc                      |   6 +-
 gcc/jit/jit-playback.cc                      |  12 +-
 gcc/jit/jit-playback.h                       |   5 +-
 gcc/jit/jit-recording.cc                     |  76 ++++++++--
 gcc/jit/jit-recording.h                      | 110 +++++++++++++-
 gcc/jit/libgccjit.cc                         |  18 +++
 gcc/jit/libgccjit.h                          |  13 ++
 gcc/jit/libgccjit.map                        |   5 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h |   3 +
 gcc/testsuite/jit.dg/test-target-builtins.c  |  77 ++++++++++
 13 files changed, 538 insertions(+), 21 deletions(-)

diff --git a/gcc/jit/docs/topics/compatibility.rst 
b/gcc/jit/docs/topics/compatibility.rst
index 77b4c5df9979..bfef40afc2a0 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -418,7 +418,6 @@ on functions and variables:
 --------------------
 ``LIBGCCJIT_ABI_30`` covers the addition of
 :func:`gcc_jit_context_convert_vector`
-=======
 
 .. _LIBGCCJIT_ABI_31:
 
@@ -428,3 +427,12 @@ on functions and variables:
 
   * :func:`gcc_jit_context_new_rvalue_vector_perm`
   * :func:`gcc_jit_context_new_vector_access`
+
+.. _LIBGCCJIT_ABI_32:
+
+``LIBGCCJIT_ABI_32``
+--------------------
+
+``LIBGCCJIT_ABI_32`` covers the addition of a function to get target builtins:
+
+  * :func:`gcc_jit_context_get_target_builtin_function`
diff --git a/gcc/jit/docs/topics/functions.rst 
b/gcc/jit/docs/topics/functions.rst
index 804605ea9398..16e82a34c21f 100644
--- a/gcc/jit/docs/topics/functions.rst
+++ b/gcc/jit/docs/topics/functions.rst
@@ -140,6 +140,25 @@ Functions
       uses such a parameter will lead to an error being emitted within
       the context.
 
+.. function::  gcc_jit_function *\
+               gcc_jit_context_get_target_builtin_function (gcc_jit_context 
*ctxt,\
+                                                            const char *name)
+
+   Get the :type:`gcc_jit_function` for the built-in function (sometimes called
+   intrinsic functions) with the given name.  For example:
+
+   .. code-block:: c
+
+      gcc_jit_function *fn
+        = gcc_jit_context_get_target_builtin_function (ctxt, 
"__builtin_ia32_pmuldq512_mask");
+
+   .. note:: Due to technical limitations with how libgccjit interacts with
+      the insides of GCC, not all built-in functions are supported.  More
+      precisely, not all types are supported for parameters of built-in
+      functions from libgccjit.  Attempts to get a built-in function that
+      uses such a parameter will lead to an error being emitted within
+      the context.
+
 .. function::  gcc_jit_object *\
                gcc_jit_function_as_object (gcc_jit_function *func)
 
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 327e8de4f94a..047c0c284aa9 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "target.h"
 #include "jit-playback.h"
 #include "stor-layout.h"
 #include "debug.h"
@@ -34,8 +35,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "diagnostic-format-text.h"
 #include "make-unique.h"
+#include "print-tree.h"
 
 #include <mpfr.h>
+#include <unordered_map>
+
+using namespace gcc::jit;
 
 /* Attribute handling.  */
 
@@ -140,6 +145,14 @@ static const struct attribute_spec::exclusions 
attr_target_exclusions[] =
   ATTR_EXCL (NULL, false, false, false),
 };
 
+/* These variables act as a cache for the target builtins. This is needed in
+   order to be able to type-check the calls since we can only get those types
+   in the playback phase while we need them in the recording phase.  */
+hash_map<nofree_string_hash, tree> target_builtins{};
+std::unordered_map<std::string, recording::function_type*> 
target_function_types
+{};
+recording::context target_builtins_ctxt{NULL};
+
 /* Table of machine-independent attributes supported in libgccjit.  */
 static const attribute_spec jit_gnu_attributes[] =
 {
@@ -1079,6 +1092,7 @@ jit_langhook_init (void)
 
   build_common_tree_nodes (flag_signed_char);
 
+  target_builtins.empty ();
   build_common_builtin_nodes ();
 
   /* The default precision for floating point numbers.  This is used
@@ -1086,6 +1100,8 @@ jit_langhook_init (void)
      eventually be controllable by a command line option.  */
   mpfr_set_default_prec (256);
 
+  targetm.init_builtins ();
+
   return true;
 }
 
@@ -1153,11 +1169,198 @@ jit_langhook_type_for_mode (machine_mode mode, int 
unsignedp)
   return NULL;
 }
 
-/* Record a builtin function.  We just ignore builtin functions.  */
+recording::type* tree_type_to_jit_type (tree type)
+{
+  if (TREE_CODE (type) == VECTOR_TYPE)
+  {
+    tree inner_type = TREE_TYPE (type);
+    recording::type* element_type = tree_type_to_jit_type (inner_type);
+    poly_uint64 size = TYPE_VECTOR_SUBPARTS (type);
+    long constant_size = size.to_constant ();
+    if (element_type != NULL)
+      return element_type->get_vector (constant_size);
+    return NULL;
+  }
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    // For __builtin_ms_va_start.
+    // FIXME: wrong type.
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_VOID);
+  if (TREE_CODE (type) == RECORD_TYPE)
+    // For __builtin_sysv_va_copy.
+    // FIXME: wrong type.
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_VOID);
+  /* TODO: Remove when we add support for sized floating-point types.  */
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    if (type == FLOATN_NX_TYPE_NODE (i))
+      // FIXME: wrong type.
+      return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                                GCC_JIT_TYPE_VOID);
+  if (type == void_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_VOID);
+  else if (type == ptr_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_VOID_PTR);
+  else if (type == const_ptr_type_node)
+  {
+    // Void const ptr.
+    recording::type* result =
+      new recording::memento_of_get_type (&target_builtins_ctxt,
+                                         GCC_JIT_TYPE_VOID_PTR);
+    return new recording::memento_of_get_const (result);
+  }
+  else if (type == unsigned_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_UNSIGNED_INT);
+  else if (type == long_unsigned_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_UNSIGNED_LONG);
+  else if (type == integer_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_INT);
+  else if (type == long_integer_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_LONG);
+  else if (type == long_long_integer_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_LONG_LONG);
+  else if (type == signed_char_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_SIGNED_CHAR);
+  else if (type == char_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_CHAR);
+  else if (type == unsigned_intQI_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_UINT8_T);
+  else if (type == short_integer_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_SHORT);
+  else if (type == short_unsigned_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_UNSIGNED_SHORT);
+  else if (type == complex_float_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_COMPLEX_FLOAT);
+  else if (type == complex_double_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_COMPLEX_DOUBLE);
+  else if (type == complex_long_double_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                           GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
+  else if (type == float_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_FLOAT);
+  else if (type == double_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_DOUBLE);
+  else if (type == long_double_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_LONG_DOUBLE);
+  else if (type == bfloat16_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_BFLOAT16);
+  else if (type == dfloat128_type_node)
+    // FIXME: wrong type.
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_VOID);
+  else if (type == long_long_unsigned_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+  else if (type == boolean_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_BOOL);
+  else if (type == size_type_node)
+    return new recording::memento_of_get_type (&target_builtins_ctxt,
+                                              GCC_JIT_TYPE_SIZE_T);
+  else if (TREE_CODE (type) == POINTER_TYPE)
+  {
+    tree inner_type = TREE_TYPE (type);
+    recording::type* element_type = tree_type_to_jit_type (inner_type);
+    return element_type->get_pointer ();
+  }
+  else
+  {
+    // Attempt to find an unqualified type when the current type has 
qualifiers.
+    tree tp = TYPE_MAIN_VARIANT (type);
+    for ( ; tp != NULL ; tp = TYPE_NEXT_VARIANT (tp))
+    {
+      if (TYPE_QUALS (tp) == 0 && type != tp)
+      {
+       recording::type* result = tree_type_to_jit_type (tp);
+       if (result != NULL)
+       {
+         if (TYPE_READONLY (tp))
+           result = new recording::memento_of_get_const (result);
+         if (TYPE_VOLATILE (tp))
+           result = new recording::memento_of_get_volatile (result);
+         return result;
+       }
+      }
+    }
+
+    fprintf (stderr, "Unknown type:\n");
+    debug_tree (type);
+    abort ();
+  }
+
+  return NULL;
+}
+
+/* Record a builtin function.  We save their types to be able to check types
+   in recording and for reflection.  */
 
 static tree
 jit_langhook_builtin_function (tree decl)
 {
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+  {
+    const char* name = IDENTIFIER_POINTER (DECL_NAME (decl));
+    target_builtins.put (name, decl);
+
+    std::string string_name (name);
+    if (target_function_types.count (string_name) == 0)
+    {
+      tree function_type = TREE_TYPE (decl);
+      tree arg = TYPE_ARG_TYPES (function_type);
+      bool is_variadic = false;
+
+      auto_vec <recording::type *> param_types;
+
+      while (arg != void_list_node)
+      {
+       if (arg == NULL)
+       {
+         is_variadic = true;
+         break;
+       }
+       if (arg != void_list_node)
+       {
+         recording::type* arg_type = tree_type_to_jit_type (TREE_VALUE (arg));
+         if (arg_type == NULL)
+           return decl;
+         param_types.safe_push (arg_type);
+       }
+       arg = TREE_CHAIN (arg);
+      }
+
+      tree result_type = TREE_TYPE (function_type);
+      recording::type* return_type = tree_type_to_jit_type (result_type);
+
+      if (return_type == NULL)
+       return decl;
+
+      recording::function_type* func_type =
+       new recording::function_type (&target_builtins_ctxt, return_type,
+                                     param_types.length (),
+                                     param_types.address (), is_variadic,
+                                     false);
+
+      target_function_types[string_name] = func_type;
+    }
+  }
   return decl;
 }
 
diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc
index 0c13c8db5860..4d08486f00d5 100644
--- a/gcc/jit/jit-builtins.cc
+++ b/gcc/jit/jit-builtins.cc
@@ -215,7 +215,8 @@ builtins_manager::make_builtin_function (enum 
built_in_function builtin_id)
                             param_types.length (),
                             params,
                             func_type->is_variadic (),
-                            builtin_id);
+                            builtin_id,
+                            false);
   delete[] params;
 
   /* PR/64020 - If the client code is using builtin cos or sin,
@@ -582,7 +583,8 @@ builtins_manager::make_fn_type (enum jit_builtin_type,
   result = m_ctxt->new_function_type (return_type,
                                      num_args,
                                      param_types,
-                                     is_variadic);
+                                     is_variadic,
+                                     false);
 
  error:
   delete[] param_types;
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 142a8dbab15d..e8887e96c8e0 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -572,7 +572,8 @@ new_function (location *loc,
                                          std::string>> &string_attributes,
              const std::vector<std::pair<gcc_jit_fn_attribute,
                                          std::vector<int>>>
-                                         &int_array_attributes)
+                                         &int_array_attributes,
+             bool is_target_builtin)
 {
   int i;
   param *param;
@@ -608,6 +609,15 @@ new_function (location *loc,
 
   tree fn_attributes = NULL_TREE;
 
+  if (is_target_builtin)
+  {
+    tree *decl = target_builtins.get (name);
+    if (decl != NULL)
+      fndecl = *decl;
+    else
+      add_error (loc, "cannot find target builtin %s", name);
+  }
+
   if (builtin_id)
     {
       gcc_assert (loc == NULL);
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 8097b80b234a..2f5e41155674 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -121,7 +121,8 @@ public:
                                            std::string>> &string_attributes,
                const std::vector<std::pair<gcc_jit_fn_attribute,
                                            std::vector<int>>>
-                                           &int_array_attributes);
+                                           &int_array_attributes,
+               bool is_target_builtin);
 
   lvalue *
   new_global (location *loc,
@@ -869,4 +870,6 @@ extern playback::context *active_playback_ctxt;
 
 } // namespace gcc
 
+extern hash_map<nofree_string_hash, tree> target_builtins;
+
 #endif /* JIT_PLAYBACK_H */
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 90ac5bdafffc..7c1b3fdde410 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -935,14 +935,16 @@ recording::function_type *
 recording::context::new_function_type (recording::type *return_type,
                                       int num_params,
                                       recording::type **param_types,
-                                      int is_variadic)
+                                      int is_variadic,
+                                      bool is_target_builtin)
 {
   recording::function_type *fn_type
     = new function_type (this,
                         return_type,
                         num_params,
                         param_types,
-                        is_variadic);
+                        is_variadic,
+                        is_target_builtin);
   record (fn_type);
   return fn_type;
 }
@@ -964,7 +966,8 @@ recording::context::new_function_ptr_type 
(recording::location *, /* unused loc
     = new_function_type (return_type,
                         num_params,
                         param_types,
-                        is_variadic);
+                        is_variadic,
+                        false);
 
   /* Return a pointer-type to the function type.  */
   return fn_type->get_pointer ();
@@ -1007,7 +1010,7 @@ recording::context::new_function (recording::location 
*loc,
                             loc, kind, return_type,
                             new_string (name),
                             num_params, params, is_variadic,
-                            builtin_id);
+                            builtin_id, false);
   record (result);
   m_functions.safe_push (result);
 
@@ -1046,6 +1049,53 @@ recording::context::get_builtin_function (const char 
*name)
   return bm->get_builtin_function (name);
 }
 
+/* Create a recording::function instance for a target-specific builtin.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_target_builtin_function.  */
+
+recording::function *
+recording::context::get_target_builtin_function (const char *name)
+{
+  const char *asm_name = name;
+  if (target_function_types.count (name) == 0)
+  {
+    fprintf (stderr, "Cannot find target builtin %s\n", name);
+    return NULL;
+  }
+
+  recording::function_type* func_type = target_function_types[name]
+    ->copy (this)->dyn_cast_function_type ();
+  const vec<type *>& param_types = func_type->get_param_types ();
+  recording::param **params = new recording::param *[param_types.length ()];
+
+  int i;
+  recording::type *param_type;
+  FOR_EACH_VEC_ELT (param_types, i, param_type)
+    {
+      char buf[16];
+      snprintf (buf, 16, "arg%d", i);
+      params[i] = new_param (NULL,
+                            param_type,
+                            buf);
+  }
+
+  recording::function *result =
+    new recording::function (this,
+         NULL,
+         GCC_JIT_FUNCTION_IMPORTED,
+         func_type->get_return_type (),
+         new_string (asm_name),
+         param_types.length (),
+         params,
+         func_type->is_variadic (),
+         BUILT_IN_NONE,
+         true);
+  record (result);
+
+  return result;
+}
+
 /* Create a recording::global instance and add it to this context's list
    of mementos.
 
@@ -3251,11 +3301,13 @@ recording::function_type::function_type (context *ctxt,
                                         type *return_type,
                                         int num_params,
                                         type **param_types,
-                                        int is_variadic)
+                                        int is_variadic,
+                                        bool is_target_builtin)
 : type (ctxt),
   m_return_type (return_type),
   m_param_types (),
-  m_is_variadic (is_variadic)
+  m_is_variadic (is_variadic),
+  m_is_target_builtin (is_target_builtin)
 {
   for (int i = 0; i< num_params; i++)
     m_param_types.safe_push (param_types[i]);
@@ -4204,7 +4256,8 @@ recording::function::function (context *ctxt,
                               int num_params,
                               recording::param **params,
                               int is_variadic,
-                              enum built_in_function builtin_id)
+                              enum built_in_function builtin_id,
+                              bool is_target_builtin)
 : memento (ctxt),
   m_loc (loc),
   m_kind (kind),
@@ -4218,7 +4271,8 @@ recording::function::function (context *ctxt,
   m_fn_ptr_type (NULL),
   m_attributes (),
   m_string_attributes (),
-  m_int_array_attributes ()
+  m_int_array_attributes (),
+  m_is_target_builtin (is_target_builtin)
 {
   for (int i = 0; i< num_params; i++)
     {
@@ -4280,7 +4334,8 @@ recording::function::replay_into (replayer *r)
                                     m_builtin_id,
                                     m_attributes,
                                     m_string_attributes,
-                                    m_int_array_attributes));
+                                    m_int_array_attributes,
+                                    m_is_target_builtin));
 }
 
 /* Create a recording::local instance and add it to
@@ -4547,7 +4602,8 @@ recording::function::get_address (recording::location 
*loc)
        = m_ctxt->new_function_type (m_return_type,
                                     m_params.length (),
                                     param_types.address (),
-                                    m_is_variadic);
+                                    m_is_variadic,
+                                    m_is_target_builtin);
       m_fn_ptr_type = fn_type->get_pointer ();
     }
   gcc_assert (m_fn_ptr_type);
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index ab4b0ff35b65..fa254875b20e 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -28,12 +28,16 @@ along with GCC; see the file COPYING3.  If not see
 #include <string>
 #include <vector>
 
+#include <unordered_map>
+
 class timer;
 
+extern std::unordered_map<std::string, gcc::jit::recording::function_type*>
+  target_function_types;
+
 namespace gcc {
 
 namespace jit {
-
 extern const char * const unary_op_reproducer_strings[];
 extern const char * const binary_op_reproducer_strings[];
 
@@ -125,7 +129,8 @@ public:
   new_function_type (type *return_type,
                     int num_params,
                     type **param_types,
-                    int is_variadic);
+                    int is_variadic,
+                    bool is_target_builtin);
 
   type *
   new_function_ptr_type (location *loc,
@@ -152,6 +157,9 @@ public:
   function *
   get_builtin_function (const char *name);
 
+  function *
+  get_target_builtin_function (const char *name);
+
   lvalue *
   new_global (location *loc,
              enum gcc_jit_global_kind kind,
@@ -574,6 +582,8 @@ public:
      these types.  */
   virtual size_t get_size () { gcc_unreachable (); }
 
+  virtual type* copy (context* ctxt) = 0;
+
   /* Dynamic casts.  */
   virtual function_type *dyn_cast_function_type () { return NULL; }
   virtual function_type *as_a_function_type() { gcc_unreachable (); return 
NULL; }
@@ -661,6 +671,11 @@ public:
 
   size_t get_size () final override;
 
+  type* copy (context* ctxt) final override
+  {
+    return ctxt->get_type (m_kind);
+  }
+
   bool accepts_writes_from (type *rtype) final override
   {
     if (m_kind == GCC_JIT_TYPE_VOID_PTR)
@@ -705,6 +720,13 @@ public:
 
   type *dereference () final override { return m_other_type; }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new memento_of_get_pointer (m_other_type->copy (ctxt));
+    ctxt->record (result);
+    return result;
+  }
+
   size_t get_size () final override;
 
   bool accepts_writes_from (type *rtype) final override;
@@ -768,6 +790,13 @@ public:
     return false;
   }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new memento_of_get_const (m_other_type->copy (ctxt));
+    ctxt->record (result);
+    return result;
+  }
+
   /* Strip off the "const", giving the underlying type.  */
   type *unqualified () final override { return m_other_type; }
 
@@ -801,6 +830,13 @@ public:
     return m_other_type->is_same_type_as (other->is_volatile ());
   }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new memento_of_get_volatile (m_other_type->copy (ctxt));
+    ctxt->record (result);
+    return result;
+  }
+
   /* Strip off the "volatile", giving the underlying type.  */
   type *unqualified () final override { return m_other_type; }
 
@@ -827,6 +863,13 @@ public:
     return m_other_type->is_same_type_as (other->is_restrict ());
   }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new memento_of_get_restrict (m_other_type->copy (ctxt));
+    ctxt->record (result);
+    return result;
+  }
+
   /* Strip off the "restrict", giving the underlying type.  */
   type *unqualified () final override { return m_other_type; }
 
@@ -860,6 +903,14 @@ public:
 
   type *is_aligned () final override { return m_other_type; }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new memento_of_get_aligned (m_other_type->copy (ctxt),
+                                              m_alignment_in_bytes);
+    ctxt->record (result);
+    return result;
+  }
+
   /* Strip off the alignment, giving the underlying type.  */
   type *unqualified () final override { return m_other_type; }
 
@@ -902,6 +953,13 @@ public:
     return true;
   }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new vector_type (m_other_type->copy (ctxt), m_num_units);
+    ctxt->record (result);
+    return result;
+  }
+
   size_t get_num_units () const { return m_num_units; }
 
   vector_type *dyn_cast_vector_type () final override { return this; }
@@ -955,6 +1013,14 @@ class array_type : public type
 
   array_type *dyn_cast_array_type () final override { return this; }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new array_type (ctxt, m_loc, m_element_type->copy (ctxt),
+                                  m_num_elements);
+    ctxt->record (result);
+    return result;
+  }
+
   bool is_int () const final override { return false; }
   bool is_float () const final override { return false; }
   bool is_bool () const final override { return false; }
@@ -982,7 +1048,8 @@ public:
                 type *return_type,
                 int num_params,
                 type **param_types,
-                int is_variadic);
+                int is_variadic,
+                bool is_target_builtin);
 
   type *dereference () final override;
   function_type *dyn_cast_function_type () final override { return this; }
@@ -990,6 +1057,20 @@ public:
 
   bool is_same_type_as (type *other) final override;
 
+  type* copy (context* ctxt) final override
+  {
+    auto_vec<type *> new_params{};
+    for (size_t i = 0; i < m_param_types.length (); i++)
+      new_params.safe_push (m_param_types[i]->copy (ctxt));
+
+    type* result = new function_type (ctxt, m_return_type->copy (ctxt),
+                                     m_param_types.length (),
+                                     new_params.address (),
+                                     m_is_variadic, m_is_target_builtin);
+    ctxt->record (result);
+    return result;
+  }
+
   bool is_int () const final override { return false; }
   bool is_float () const final override { return false; }
   bool is_bool () const final override { return false; }
@@ -1018,6 +1099,7 @@ private:
   type *m_return_type;
   auto_vec<type *> m_param_types;
   int m_is_variadic;
+  bool m_is_target_builtin;
 };
 
 class field : public memento
@@ -1119,9 +1201,11 @@ public:
     return static_cast <playback::compound_type *> (m_playback_obj);
   }
 
-private:
+protected:
   location *m_loc;
   string *m_name;
+
+private:
   fields *m_fields;
 };
 
@@ -1134,6 +1218,13 @@ public:
 
   struct_ *dyn_cast_struct () final override { return this; }
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new struct_ (ctxt, m_loc, m_name);
+    ctxt->record (result);
+    return result;
+  }
+
   type *
   as_type () { return this; }
 
@@ -1181,6 +1272,13 @@ public:
 
   void replay_into (replayer *r) final override;
 
+  type* copy (context* ctxt) final override
+  {
+    type* result = new union_ (ctxt, m_loc, m_name);
+    ctxt->record (result);
+    return result;
+  }
+
   bool is_union () const final override { return true; }
 
 private:
@@ -1407,7 +1505,8 @@ public:
            int num_params,
            param **params,
            int is_variadic,
-           enum built_in_function builtin_id);
+           enum built_in_function builtin_id,
+           bool is_target_builtin);
 
   void replay_into (replayer *r) final override;
 
@@ -1469,6 +1568,7 @@ private:
   std::vector<gcc_jit_fn_attribute> m_attributes;
   std::vector<std::pair<gcc_jit_fn_attribute, std::string>> 
m_string_attributes;
   std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> 
m_int_array_attributes;
+  bool m_is_target_builtin;
 };
 
 class block : public memento
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 3a7a4e26931f..17cefa601a93 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -1774,6 +1774,24 @@ gcc_jit_context_new_array_constructor (gcc_jit_context 
*ctxt,
     reinterpret_cast<gcc::jit::recording::rvalue**>(values));
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::get_target_builtin_function method, in
+   jit-recording.c.  */
+
+gcc_jit_function *
+gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt,
+                                            const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");
+
+  return static_cast <gcc_jit_function *> (
+    ctxt->get_target_builtin_function (name));
+}
+
 /* Public entrypoint.  See description in libgccjit.h.  */
 
 extern gcc_jit_lvalue *
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 1274a1bb61b6..18a343628b22 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1040,6 +1040,19 @@ extern gcc_jit_lvalue *
 gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
                                       gcc_jit_rvalue *init_value);
 
+#define LIBGCCJIT_HAVE_gcc_jit_context_get_target_builtin_function
+
+/* Create a reference to a machine-specific builtin function (sometimes called
+   intrinsic functions).
+
+   This API entrypoint was added in LIBGCCJIT_ABI_32; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_context_get_target_builtin_function
+*/
+extern gcc_jit_function *
+gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt,
+                                            const char *name);
+
 #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
 
 /* Set an initial value for a global, which must be an array of
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index d8fb86eef3db..b1c14b51d95f 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -310,3 +310,8 @@ LIBGCCJIT_ABI_31 {
     gcc_jit_context_new_vector_access;
     gcc_jit_context_new_rvalue_vector_perm;
 } LIBGCCJIT_ABI_30;
+
+LIBGCCJIT_ABI_32 {
+  global:
+    gcc_jit_context_get_target_builtin_function;
+} LIBGCCJIT_ABI_31;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h 
b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 00b7d8305bfe..6b602f95a5bb 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -387,6 +387,9 @@
 #undef create_code
 #undef verify_code
 
+/* test-target-builtins.c: This can't be in the testcases array as it
+   is target-specific.  */
+
 /* test-string-literal.c */
 #define create_code create_code_string_literal
 #define verify_code verify_code_string_literal
diff --git a/gcc/testsuite/jit.dg/test-target-builtins.c 
b/gcc/testsuite/jit.dg/test-target-builtins.c
new file mode 100644
index 000000000000..0ffb48e97f64
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-target-builtins.c
@@ -0,0 +1,77 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  CHECK_NON_NULL (gcc_jit_context_get_target_builtin_function (ctxt, 
"__builtin_ia32_xgetbv"));
+  gcc_jit_function *builtin_eh_pointer = 
gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_eh_pointer");
+  CHECK_NON_NULL (builtin_eh_pointer);
+
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *void_ptr =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+  gcc_jit_function *func_main =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 int_type,
+                                 "main",
+                                 0, NULL,
+                                 0);
+  gcc_jit_rvalue *zero = gcc_jit_context_zero (ctxt, int_type);
+  gcc_jit_block *block = gcc_jit_function_new_block (func_main, NULL);
+  gcc_jit_lvalue *variable = gcc_jit_function_new_local(func_main, NULL, 
void_ptr, "variable");
+  gcc_jit_block_add_assignment (block, NULL, variable,
+    gcc_jit_context_new_call (ctxt, NULL, builtin_eh_pointer, 1, &zero));
+  gcc_jit_block_end_with_return (block, NULL, zero);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+}
+
+int
+main (int argc, char **argv)
+{
+  /*  This is the same as the main provided by harness.h, but it first create 
a dummy context and compile
+      in order to add the target builtins to libgccjit's internal state.  */
+  gcc_jit_context *ctxt;
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fail ("gcc_jit_context_acquire failed");
+      return -1;
+    }
+  gcc_jit_result *result;
+  result = gcc_jit_context_compile (ctxt);
+  gcc_jit_result_release (result);
+  gcc_jit_context_release (ctxt);
+
+  int i;
+
+  for (i = 1; i <= 5; i++)
+    {
+      snprintf (test, sizeof (test),
+               "%s iteration %d of %d",
+                extract_progname (argv[0]),
+                i, 5);
+
+      //printf ("ITERATION %d\n", i);
+      test_jit (argv[0], NULL);
+      //printf ("\n");
+    }
+
+  totals ();
+
+  return 0;
+}

Reply via email to