Skip to content

Commit 87f0136

Browse files
committed
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.
1 parent beab0a3 commit 87f0136

File tree

13 files changed

+538
-21
lines changed

13 files changed

+538
-21
lines changed

gcc/jit/docs/topics/compatibility.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,6 @@ on functions and variables:
418418
--------------------
419419
``LIBGCCJIT_ABI_30`` covers the addition of
420420
:func:`gcc_jit_context_convert_vector`
421-
=======
422421

423422
.. _LIBGCCJIT_ABI_31:
424423

@@ -428,3 +427,12 @@ on functions and variables:
428427

429428
* :func:`gcc_jit_context_new_rvalue_vector_perm`
430429
* :func:`gcc_jit_context_new_vector_access`
430+
431+
.. _LIBGCCJIT_ABI_32:
432+
433+
``LIBGCCJIT_ABI_32``
434+
--------------------
435+
436+
``LIBGCCJIT_ABI_32`` covers the addition of a function to get target builtins:
437+
438+
* :func:`gcc_jit_context_get_target_builtin_function`

gcc/jit/docs/topics/functions.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ Functions
140140
uses such a parameter will lead to an error being emitted within
141141
the context.
142142

143+
.. function:: gcc_jit_function *\
144+
gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt,\
145+
const char *name)
146+
147+
Get the :type:`gcc_jit_function` for the built-in function (sometimes called
148+
intrinsic functions) with the given name. For example:
149+
150+
.. code-block:: c
151+
152+
gcc_jit_function *fn
153+
= gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_ia32_pmuldq512_mask");
154+
155+
.. note:: Due to technical limitations with how libgccjit interacts with
156+
the insides of GCC, not all built-in functions are supported. More
157+
precisely, not all types are supported for parameters of built-in
158+
functions from libgccjit. Attempts to get a built-in function that
159+
uses such a parameter will lead to an error being emitted within
160+
the context.
161+
143162
.. function:: gcc_jit_object *\
144163
gcc_jit_function_as_object (gcc_jit_function *func)
145164

gcc/jit/dummy-frontend.cc

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
2121
#include "config.h"
2222
#include "system.h"
2323
#include "coretypes.h"
24+
#include "target.h"
2425
#include "jit-playback.h"
2526
#include "stor-layout.h"
2627
#include "debug.h"
@@ -34,8 +35,12 @@ along with GCC; see the file COPYING3. If not see
3435
#include "target.h"
3536
#include "diagnostic-format-text.h"
3637
#include "make-unique.h"
38+
#include "print-tree.h"
3739

3840
#include <mpfr.h>
41+
#include <unordered_map>
42+
43+
using namespace gcc::jit;
3944

4045
/* Attribute handling. */
4146

@@ -140,6 +145,14 @@ static const struct attribute_spec::exclusions attr_target_exclusions[] =
140145
ATTR_EXCL (NULL, false, false, false),
141146
};
142147

148+
/* These variables act as a cache for the target builtins. This is needed in
149+
order to be able to type-check the calls since we can only get those types
150+
in the playback phase while we need them in the recording phase. */
151+
hash_map<nofree_string_hash, tree> target_builtins{};
152+
std::unordered_map<std::string, recording::function_type*> target_function_types
153+
{};
154+
recording::context target_builtins_ctxt{NULL};
155+
143156
/* Table of machine-independent attributes supported in libgccjit. */
144157
static const attribute_spec jit_gnu_attributes[] =
145158
{
@@ -1079,13 +1092,16 @@ jit_langhook_init (void)
10791092

10801093
build_common_tree_nodes (flag_signed_char);
10811094

1095+
target_builtins.empty ();
10821096
build_common_builtin_nodes ();
10831097

10841098
/* The default precision for floating point numbers. This is used
10851099
for floating point constants with abstract type. This may
10861100
eventually be controllable by a command line option. */
10871101
mpfr_set_default_prec (256);
10881102

1103+
targetm.init_builtins ();
1104+
10891105
return true;
10901106
}
10911107

@@ -1153,11 +1169,198 @@ jit_langhook_type_for_mode (machine_mode mode, int unsignedp)
11531169
return NULL;
11541170
}
11551171

1156-
/* Record a builtin function. We just ignore builtin functions. */
1172+
recording::type* tree_type_to_jit_type (tree type)
1173+
{
1174+
if (TREE_CODE (type) == VECTOR_TYPE)
1175+
{
1176+
tree inner_type = TREE_TYPE (type);
1177+
recording::type* element_type = tree_type_to_jit_type (inner_type);
1178+
poly_uint64 size = TYPE_VECTOR_SUBPARTS (type);
1179+
long constant_size = size.to_constant ();
1180+
if (element_type != NULL)
1181+
return element_type->get_vector (constant_size);
1182+
return NULL;
1183+
}
1184+
if (TREE_CODE (type) == REFERENCE_TYPE)
1185+
// For __builtin_ms_va_start.
1186+
// FIXME: wrong type.
1187+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1188+
GCC_JIT_TYPE_VOID);
1189+
if (TREE_CODE (type) == RECORD_TYPE)
1190+
// For __builtin_sysv_va_copy.
1191+
// FIXME: wrong type.
1192+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1193+
GCC_JIT_TYPE_VOID);
1194+
/* TODO: Remove when we add support for sized floating-point types. */
1195+
for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
1196+
if (type == FLOATN_NX_TYPE_NODE (i))
1197+
// FIXME: wrong type.
1198+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1199+
GCC_JIT_TYPE_VOID);
1200+
if (type == void_type_node)
1201+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1202+
GCC_JIT_TYPE_VOID);
1203+
else if (type == ptr_type_node)
1204+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1205+
GCC_JIT_TYPE_VOID_PTR);
1206+
else if (type == const_ptr_type_node)
1207+
{
1208+
// Void const ptr.
1209+
recording::type* result =
1210+
new recording::memento_of_get_type (&target_builtins_ctxt,
1211+
GCC_JIT_TYPE_VOID_PTR);
1212+
return new recording::memento_of_get_const (result);
1213+
}
1214+
else if (type == unsigned_type_node)
1215+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1216+
GCC_JIT_TYPE_UNSIGNED_INT);
1217+
else if (type == long_unsigned_type_node)
1218+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1219+
GCC_JIT_TYPE_UNSIGNED_LONG);
1220+
else if (type == integer_type_node)
1221+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1222+
GCC_JIT_TYPE_INT);
1223+
else if (type == long_integer_type_node)
1224+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1225+
GCC_JIT_TYPE_LONG);
1226+
else if (type == long_long_integer_type_node)
1227+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1228+
GCC_JIT_TYPE_LONG_LONG);
1229+
else if (type == signed_char_type_node)
1230+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1231+
GCC_JIT_TYPE_SIGNED_CHAR);
1232+
else if (type == char_type_node)
1233+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1234+
GCC_JIT_TYPE_CHAR);
1235+
else if (type == unsigned_intQI_type_node)
1236+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1237+
GCC_JIT_TYPE_UINT8_T);
1238+
else if (type == short_integer_type_node)
1239+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1240+
GCC_JIT_TYPE_SHORT);
1241+
else if (type == short_unsigned_type_node)
1242+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1243+
GCC_JIT_TYPE_UNSIGNED_SHORT);
1244+
else if (type == complex_float_type_node)
1245+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1246+
GCC_JIT_TYPE_COMPLEX_FLOAT);
1247+
else if (type == complex_double_type_node)
1248+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1249+
GCC_JIT_TYPE_COMPLEX_DOUBLE);
1250+
else if (type == complex_long_double_type_node)
1251+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1252+
GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
1253+
else if (type == float_type_node)
1254+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1255+
GCC_JIT_TYPE_FLOAT);
1256+
else if (type == double_type_node)
1257+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1258+
GCC_JIT_TYPE_DOUBLE);
1259+
else if (type == long_double_type_node)
1260+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1261+
GCC_JIT_TYPE_LONG_DOUBLE);
1262+
else if (type == bfloat16_type_node)
1263+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1264+
GCC_JIT_TYPE_BFLOAT16);
1265+
else if (type == dfloat128_type_node)
1266+
// FIXME: wrong type.
1267+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1268+
GCC_JIT_TYPE_VOID);
1269+
else if (type == long_long_unsigned_type_node)
1270+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1271+
GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
1272+
else if (type == boolean_type_node)
1273+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1274+
GCC_JIT_TYPE_BOOL);
1275+
else if (type == size_type_node)
1276+
return new recording::memento_of_get_type (&target_builtins_ctxt,
1277+
GCC_JIT_TYPE_SIZE_T);
1278+
else if (TREE_CODE (type) == POINTER_TYPE)
1279+
{
1280+
tree inner_type = TREE_TYPE (type);
1281+
recording::type* element_type = tree_type_to_jit_type (inner_type);
1282+
return element_type->get_pointer ();
1283+
}
1284+
else
1285+
{
1286+
// Attempt to find an unqualified type when the current type has qualifiers.
1287+
tree tp = TYPE_MAIN_VARIANT (type);
1288+
for ( ; tp != NULL ; tp = TYPE_NEXT_VARIANT (tp))
1289+
{
1290+
if (TYPE_QUALS (tp) == 0 && type != tp)
1291+
{
1292+
recording::type* result = tree_type_to_jit_type (tp);
1293+
if (result != NULL)
1294+
{
1295+
if (TYPE_READONLY (tp))
1296+
result = new recording::memento_of_get_const (result);
1297+
if (TYPE_VOLATILE (tp))
1298+
result = new recording::memento_of_get_volatile (result);
1299+
return result;
1300+
}
1301+
}
1302+
}
1303+
1304+
fprintf (stderr, "Unknown type:\n");
1305+
debug_tree (type);
1306+
abort ();
1307+
}
1308+
1309+
return NULL;
1310+
}
1311+
1312+
/* Record a builtin function. We save their types to be able to check types
1313+
in recording and for reflection. */
11571314

11581315
static tree
11591316
jit_langhook_builtin_function (tree decl)
11601317
{
1318+
if (TREE_CODE (decl) == FUNCTION_DECL)
1319+
{
1320+
const char* name = IDENTIFIER_POINTER (DECL_NAME (decl));
1321+
target_builtins.put (name, decl);
1322+
1323+
std::string string_name (name);
1324+
if (target_function_types.count (string_name) == 0)
1325+
{
1326+
tree function_type = TREE_TYPE (decl);
1327+
tree arg = TYPE_ARG_TYPES (function_type);
1328+
bool is_variadic = false;
1329+
1330+
auto_vec <recording::type *> param_types;
1331+
1332+
while (arg != void_list_node)
1333+
{
1334+
if (arg == NULL)
1335+
{
1336+
is_variadic = true;
1337+
break;
1338+
}
1339+
if (arg != void_list_node)
1340+
{
1341+
recording::type* arg_type = tree_type_to_jit_type (TREE_VALUE (arg));
1342+
if (arg_type == NULL)
1343+
return decl;
1344+
param_types.safe_push (arg_type);
1345+
}
1346+
arg = TREE_CHAIN (arg);
1347+
}
1348+
1349+
tree result_type = TREE_TYPE (function_type);
1350+
recording::type* return_type = tree_type_to_jit_type (result_type);
1351+
1352+
if (return_type == NULL)
1353+
return decl;
1354+
1355+
recording::function_type* func_type =
1356+
new recording::function_type (&target_builtins_ctxt, return_type,
1357+
param_types.length (),
1358+
param_types.address (), is_variadic,
1359+
false);
1360+
1361+
target_function_types[string_name] = func_type;
1362+
}
1363+
}
11611364
return decl;
11621365
}
11631366

gcc/jit/jit-builtins.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id)
215215
param_types.length (),
216216
params,
217217
func_type->is_variadic (),
218-
builtin_id);
218+
builtin_id,
219+
false);
219220
delete[] params;
220221

221222
/* 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,
582583
result = m_ctxt->new_function_type (return_type,
583584
num_args,
584585
param_types,
585-
is_variadic);
586+
is_variadic,
587+
false);
586588

587589
error:
588590
delete[] param_types;

gcc/jit/jit-playback.cc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,8 @@ new_function (location *loc,
572572
std::string>> &string_attributes,
573573
const std::vector<std::pair<gcc_jit_fn_attribute,
574574
std::vector<int>>>
575-
&int_array_attributes)
575+
&int_array_attributes,
576+
bool is_target_builtin)
576577
{
577578
int i;
578579
param *param;
@@ -608,6 +609,15 @@ new_function (location *loc,
608609

609610
tree fn_attributes = NULL_TREE;
610611

612+
if (is_target_builtin)
613+
{
614+
tree *decl = target_builtins.get (name);
615+
if (decl != NULL)
616+
fndecl = *decl;
617+
else
618+
add_error (loc, "cannot find target builtin %s", name);
619+
}
620+
611621
if (builtin_id)
612622
{
613623
gcc_assert (loc == NULL);

gcc/jit/jit-playback.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ class context : public log_user
121121
std::string>> &string_attributes,
122122
const std::vector<std::pair<gcc_jit_fn_attribute,
123123
std::vector<int>>>
124-
&int_array_attributes);
124+
&int_array_attributes,
125+
bool is_target_builtin);
125126

126127
lvalue *
127128
new_global (location *loc,
@@ -869,4 +870,6 @@ extern playback::context *active_playback_ctxt;
869870

870871
} // namespace gcc
871872

873+
extern hash_map<nofree_string_hash, tree> target_builtins;
874+
872875
#endif /* JIT_PLAYBACK_H */

0 commit comments

Comments
 (0)