public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] libgccjit: Add ability to get CPU features
@ 2023-11-09 22:27 Antoni Boucher
  2023-11-09 23:04 ` David Malcolm
  0 siblings, 1 reply; 21+ messages in thread
From: Antoni Boucher @ 2023-11-09 22:27 UTC (permalink / raw)
  To: jit, gcc-patches; +Cc: David Malcolm

[-- Attachment #1: Type: text/plain, Size: 425 bytes --]

Hi.
This patch adds support for getting the CPU features in libgccjit (bug
112466)

There's a TODO in the test:
I'm not sure how to test that gcc_jit_target_info_arch returns the
correct value since it is dependant on the CPU.
Any idea on how to improve this?

Also, I created a CStringHash to be able to have a
std::unordered_set<const char *>. Is there any built-in way of doing
this?

Thanks for the review.

[-- Attachment #2: 0001-libgccjit-Add-ability-to-get-CPU-features.patch --]
[-- Type: text/x-patch, Size: 51157 bytes --]

From 302f9f0bb22deae3deb8249a9127447c3ec4f7c7 Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Mon, 26 Jun 2023 18:29:15 -0400
Subject: [PATCH] libgccjit: Add ability to get CPU features

gcc/ChangeLog:
	PR jit/112466
	* Makefile.in (tm_jit_file_list, tm_jit_include_list, TM_JIT_H,
	JIT_TARGET_DEF, JIT_TARGET_H, JIT_TARGET_OBJS): New variables.
	(tm_jit.h, cs-tm_jit.h, jit/jit-target-hooks-def.h,
	s-jit-target-hooks-def-h): New rules.
	(s-tm-texi): Also check timestamp on jit-target.def.
	(generated_files): Add TM_JIT_H and jit/jit-target-hooks-def.h.
	(build/genhooks.o): Also depend on JIT_TARGET_DEF.
	* config.gcc (tm_jit_file, jit_target_objs, target_has_targetjitm):
	New variables.
	* config/i386/t-i386 (i386-jit.o): New rule.
	* config/t-linux (linux-jit.o): New rule.
	* configure: Regenerate.
	* configure.ac (tm_jit_file_list, tm_jit_include_list,
	jit_target_objs): Add substitutes.
	* doc/tm.texi: Regenerate.
	* doc/tm.texi.in (targetjitm): Document.
	(target_has_targetjitm): Document.
	* genhooks.cc: Include jit/jit-target.def.
	* config/default-jit.cc: New file.
	* config/i386/i386-jit.cc: New file.
	* config/i386/i386-jit.h: New file.
	* config/linux-jit.cc: New file.

gcc/jit/ChangeLog:
	PR jit/112466
	* Make-lang.in (JIT_OBJS): New variable.
	* jit-playback.cc (replay): Include jit-target.h and initialize
	target.
	* jit-playback.h (class get_target_info): New class.
	* jit-recording.cc (recording::context::get_target_info): New
	method.
	* jit-recording.h (recording::context::get_target_info): New
	method.
	* libgccjit.cc: Include jit-target.h.
	(struct gcc_jit_target_info): New struct.
	(gcc_jit_context_get_target_info, gcc_jit_target_info_release,
	gcc_jit_target_info_cpu_supports, gcc_jit_target_info_arch,
	gcc_jit_target_info_supports_128bit_int): New functions.
	* libgccjit.h (gcc_jit_context_get_target_info,
	gcc_jit_target_info_release, gcc_jit_target_info_cpu_supports,
	gcc_jit_target_info_arch, gcc_jit_target_info_supports_128bit_int):
	New functions.
	* libgccjit.map (LIBGCCJIT_ABI_26): New ABI tag.
	* docs/topics/compilation.rst: Add documentation for the
	functions gcc_jit_context_get_target_info, gcc_jit_target_info_release,
	gcc_jit_target_info_cpu_supports, gcc_jit_target_info_arch,
	gcc_jit_target_info_supports_128bit_int.
	* docs/topics/compatibility.rst (LIBGCCJIT_ABI_26): New ABI tag.
	* jit-target-def.h: New file.
	* jit-target.cc: New file.
	* jit-target.def: New file.
	* jit-target.h: New file.

gcc/testsuite/ChangeLog:
	PR jit/112466
	* jit.dg/all-non-failing-tests.h: Mention
	test-target-info.c.
	* jit.dg/test-target-info.c: New test.
---
 gcc/Makefile.in                              |  29 ++-
 gcc/config.gcc                               |  21 ++
 gcc/config/default-jit.cc                    |  29 +++
 gcc/config/i386/i386-jit.cc                  | 195 +++++++++++++++++++
 gcc/config/i386/i386-jit.h                   |  22 +++
 gcc/config/i386/t-i386                       |   4 +
 gcc/config/linux-jit.cc                      |  36 ++++
 gcc/config/t-linux                           |   4 +
 gcc/configure                                |  14 ++
 gcc/configure.ac                             |  14 ++
 gcc/doc/tm.texi                              |  26 +++
 gcc/doc/tm.texi.in                           |  16 ++
 gcc/genhooks.cc                              |   1 +
 gcc/jit/Make-lang.in                         |   8 +-
 gcc/jit/docs/topics/compatibility.rst        |  14 ++
 gcc/jit/docs/topics/compilation.rst          |  51 +++++
 gcc/jit/jit-playback.cc                      |   2 +
 gcc/jit/jit-playback.h                       |  17 +-
 gcc/jit/jit-recording.cc                     |  19 ++
 gcc/jit/jit-recording.h                      |   3 +
 gcc/jit/jit-target-def.h                     |  20 ++
 gcc/jit/jit-target.cc                        |  89 +++++++++
 gcc/jit/jit-target.def                       |  52 +++++
 gcc/jit/jit-target.h                         |  73 +++++++
 gcc/jit/libgccjit.cc                         |  43 ++++
 gcc/jit/libgccjit.h                          |  60 ++++++
 gcc/jit/libgccjit.map                        |   9 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h |   3 +
 gcc/testsuite/jit.dg/test-target-info.c      |  63 ++++++
 29 files changed, 931 insertions(+), 6 deletions(-)
 create mode 100644 gcc/config/default-jit.cc
 create mode 100644 gcc/config/i386/i386-jit.cc
 create mode 100644 gcc/config/i386/i386-jit.h
 create mode 100644 gcc/config/linux-jit.cc
 create mode 100644 gcc/jit/jit-target-def.h
 create mode 100644 gcc/jit/jit-target.cc
 create mode 100644 gcc/jit/jit-target.def
 create mode 100644 gcc/jit/jit-target.h
 create mode 100644 gcc/testsuite/jit.dg/test-target-info.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 29cec21c825..701661fbaa0 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -609,6 +609,8 @@ tm_d_file_list=@tm_d_file_list@
 tm_d_include_list=@tm_d_include_list@
 tm_rust_file_list=@tm_rust_file_list@
 tm_rust_include_list=@tm_rust_include_list@
+tm_jit_file_list=@tm_jit_file_list@
+tm_jit_include_list=@tm_jit_include_list@
 build_xm_file_list=@build_xm_file_list@
 build_xm_include_list=@build_xm_include_list@
 build_xm_defines=@build_xm_defines@
@@ -908,6 +910,7 @@ TCONFIG_H = tconfig.h $(xm_file_list)
 TM_P_H    = tm_p.h    $(tm_p_file_list) $(TREE_H)
 TM_D_H    = tm_d.h    $(tm_d_file_list)
 TM_RUST_H = tm_rust.h $(tm_rust_file_list)
+TM_JIT_H  = tm_jit.h    $(tm_jit_file_list)
 GTM_H     = tm.h      $(tm_file_list) insn-constants.h
 TM_H      = $(GTM_H) insn-flags.h $(OPTIONS_H)
 
@@ -967,11 +970,13 @@ C_TARGET_DEF = c-family/c-target.def target-hooks-macros.h
 COMMON_TARGET_DEF = common/common-target.def target-hooks-macros.h
 D_TARGET_DEF = d/d-target.def target-hooks-macros.h
 RUST_TARGET_DEF = rust/rust-target.def target-hooks-macros.h
+JIT_TARGET_DEF = jit/jit-target.def target-hooks-macros.h
 TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h
 C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF)
 COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF)
 D_TARGET_H = d/d-target.h $(D_TARGET_DEF)
 RUST_TARGET_H = rust/rust-target.h $(RUST_TARGET_DEF)
+JIT_TARGET_H = jit/jit-target.h $(JIT_TARGET_DEF)
 MACHMODE_H = machmode.h mode-classes.def
 HOOKS_H = hooks.h
 HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H)
@@ -1279,6 +1284,9 @@ CXX_TARGET_OBJS=@cxx_target_objs@
 # Target specific, D specific object file
 D_TARGET_OBJS=@d_target_objs@
 
+# Target specific, JIT specific object file
+JIT_TARGET_OBJS=@jit_target_objs@
+
 # Target specific, Fortran specific object file
 FORTRAN_TARGET_OBJS=@fortran_target_objs@
 
@@ -2023,6 +2031,7 @@ tm.h: cs-tm.h ; @true
 tm_p.h: cs-tm_p.h ; @true
 tm_d.h: cs-tm_d.h ; @true
 tm_rust.h: cs-tm_rust.h ; @true
+tm_jit.h: cs-tm_jit.h ; @true
 
 cs-config.h: Makefile
 	TARGET_CPU_DEFAULT="" \
@@ -2062,6 +2071,11 @@ cs-tm_rust.h: Makefile
 	HEADERS="$(tm_rust_include_list)" DEFINES="" \
 	$(SHELL) $(srcdir)/mkconfig.sh tm_rust.h
 
+cs-tm_jit.h: Makefile
+	TARGET_CPU_DEFAULT="" \
+	HEADERS="$(tm_jit_include_list)" DEFINES="" \
+	$(SHELL) $(srcdir)/mkconfig.sh tm_jit.h
+
 # Don't automatically run autoconf, since configure.ac might be accidentally
 # newer than configure.  Also, this writes into the source directory which
 # might be on a read-only file system.  If configured for maintainer mode
@@ -2731,6 +2745,15 @@ s-rust-target-hooks-def-h: build/genhooks$(build_exeext)
 					     rust/rust-target-hooks-def.h
 	$(STAMP) s-rust-target-hooks-def-h
 
+jit/jit-target-hooks-def.h: s-jit-target-hooks-def-h; @true
+
+s-jit-target-hooks-def-h: build/genhooks$(build_exeext)
+	$(RUN_GEN) build/genhooks$(build_exeext) "JIT Target Hook" \
+					     > tmp-jit-target-hooks-def.h
+	$(SHELL) $(srcdir)/../move-if-change tmp-jit-target-hooks-def.h \
+					     jit/jit-target-hooks-def.h
+	$(STAMP) s-jit-target-hooks-def-h
+
 # check if someone mistakenly only changed tm.texi.
 # We use a different pathname here to avoid a circular dependency.
 s-tm-texi: $(srcdir)/doc/../doc/tm.texi
@@ -2756,6 +2779,7 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
 	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/common/common-target.def \
 	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/d/d-target.def \
 	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/rust/rust-target.def \
+	    || test $(srcdir)/doc/tm.texi -nt $(srcdir)/jit/jit-target.def \
 	  ); then \
 	  echo >&2 ; \
 	  echo You should edit $(srcdir)/doc/tm.texi.in rather than $(srcdir)/doc/tm.texi . >&2 ; \
@@ -2933,6 +2957,7 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \
        gimple-match-auto.h generic-match-auto.h \
        c-family/c-target-hooks-def.h d/d-target-hooks-def.h \
        $(TM_RUST_H) rust/rust-target-hooks-def.h \
+       $(TM_JIT_H) jit/jit-target-hooks-def.h \
        case-cfn-macros.h \
        cfn-operators.pd omp-device-properties.h
 
@@ -3067,8 +3092,8 @@ build/genrecog.o : genrecog.cc $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
   $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H)		\
   $(HASH_TABLE_H) inchash.h
 build/genhooks.o : genhooks.cc $(TARGET_DEF) $(C_TARGET_DEF)		\
-  $(COMMON_TARGET_DEF) $(D_TARGET_DEF) $(RUST_TARGET_DEF) $(BCONFIG_H) \
-  $(SYSTEM_H) errors.h
+  $(COMMON_TARGET_DEF) $(D_TARGET_DEF) $(RUST_TARGET_DEF) $(JIT_TARGET_DEF) \
+  $(BCONFIG_H) $(SYSTEM_H) errors.h
 build/genmddump.o : genmddump.cc $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
   $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H)
 build/genmatch.o : genmatch.cc $(BCONFIG_H) $(SYSTEM_H) $(CORETYPES_H) \
diff --git a/gcc/config.gcc b/gcc/config.gcc
index ba6d63e33ac..a14de7be8d6 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -149,6 +149,9 @@
 #  d_target_objs	List of extra target-dependent objects that be
 #			linked into the D compiler only.
 #
+#  jit_target_objs	List of extra target-dependent objects that be
+#			linked into the jit compiler only.
+#
 #  fortran_target_objs	List of extra target-dependent objects that be
 #			linked into the fortran compiler only.
 #
@@ -210,6 +213,8 @@
 #
 #  target_has_targetrustm	Set to yes or no depending on whether the target
 #			has its own definition of targetrustm.
+#  target_has_targetjitm	Set to yes or no depending on whether the target
+#			has its own definition of targetdm.
 
 out_file=
 common_out_file=
@@ -226,12 +231,14 @@ extra_options=
 c_target_objs=
 cxx_target_objs=
 d_target_objs=
+jit_target_objs=
 fortran_target_objs=
 rust_target_objs=
 target_has_targetcm=no
 target_has_targetm_common=yes
 target_has_targetdm=no
 target_has_targetrustm=no
+target_has_targetjitm=no
 tm_defines=
 xm_defines=
 # Set this to force installation and use of collect2.
@@ -412,6 +419,7 @@ i[34567]86-*-* | x86_64-*-*)
 	c_target_objs="i386-c.o"
 	cxx_target_objs="i386-c.o"
 	d_target_objs="i386-d.o"
+	jit_target_objs="i386-jit.o"
 	extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o i386-options.o i386-builtins.o i386-expand.o i386-features.o"
 	target_gtfiles="\$(srcdir)/config/i386/i386-builtins.cc \$(srcdir)/config/i386/i386-expand.cc \$(srcdir)/config/i386/i386-options.cc"
 	extra_options="${extra_options} fused-madd.opt"
@@ -614,6 +622,12 @@ then
 	rust_target_objs="${rust_target_objs} ${cpu_type}-rust.o"
 fi
 
+tm_jit_file=
+if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-jit.h
+then
+	tm_jit_file="${tm_jit_file} ${cpu_type}/${cpu_type}-jit.h"
+fi
+
 extra_modes=
 if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-modes.def
 then
@@ -946,9 +960,11 @@ case ${target} in
   case $target in
     *-*-*linux*)
       d_target_objs="${d_target_objs} linux-d.o"
+      jit_target_objs="${jit_target_objs} linux-jit.o"
       target_has_targetdm=yes
       rust_target_objs="${rust_target_objs} linux-rust.o"
       target_has_targetrustm=yes
+      target_has_targetjitm=yes
       ;;
     *-*-kfreebsd*-gnu)
       d_target_objs="${d_target_objs} kfreebsd-d.o"
@@ -3667,6 +3683,10 @@ if [ "$target_has_targetrustm" = "no" ]; then
   rust_target_objs="$rust_target_objs default-rust.o"
 fi
 
+if [ "$target_has_targetjitm" = "no" ]; then
+  jit_target_objs="$jit_target_objs default-jit.o"
+fi
+
 # Support for --with-cpu and related options (and a few unrelated options,
 # too).
 case ${with_cpu} in
@@ -5922,6 +5942,7 @@ case ${target} in
 		c_target_objs="${c_target_objs} ${cpu_type}-c.o"
 		cxx_target_objs="${cxx_target_objs} ${cpu_type}-c.o"
 		d_target_objs="${d_target_objs} ${cpu_type}-d.o"
+		jit_target_objs="${jit_target_objs} ${cpu_type}-jit.o"
 		tmake_file="${cpu_type}/t-${cpu_type} ${tmake_file}"
 		;;
 
diff --git a/gcc/config/default-jit.cc b/gcc/config/default-jit.cc
new file mode 100644
index 00000000000..d286d6c4caa
--- /dev/null
+++ b/gcc/config/default-jit.cc
@@ -0,0 +1,29 @@
+/* Default JIT language target hooks initializer.
+   Copyright (C) 2023 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 "tm_jit.h"
+#include "jit/jit-target.h"
+#include "jit/jit-target-def.h"
+
+/* Do not include tm.h or tm_p.h here; definitions needed by the target
+   architecture to initialize targetjitm should instead be added to
+   tm_jit.h.  */
+
+struct gcc_targetjitm targetjitm = TARGETJITM_INITIALIZER;
diff --git a/gcc/config/i386/i386-jit.cc b/gcc/config/i386/i386-jit.cc
new file mode 100644
index 00000000000..38b3f66e686
--- /dev/null
+++ b/gcc/config/i386/i386-jit.cc
@@ -0,0 +1,195 @@
+/* Subroutines for the JIT front end on the x86 architecture.
+   Copyright (C) 2023 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/>.  */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tm.h"
+#include "tm_jit.h"
+#include "jit/jit-target.h"
+#include "jit/jit-target-def.h"
+
+/* Implement TARGET_JIT_REGISTER_CPU_TARGET_INFO.  */
+
+extern const char *host_detect_local_cpu (int argc, const char **argv);
+
+#if TARGET_64BIT_DEFAULT
+const char* x86_bits = "64";
+#else
+const char* x86_bits = "32";
+#endif
+
+void
+ix86_jit_register_target_info (void)
+{
+  const char *params[] = {"arch", x86_bits};
+  const char* local_cpu = host_detect_local_cpu (2, params);
+  std::string arch = local_cpu;
+  free (const_cast <char *> (local_cpu));
+
+  const char* arg = "-march=";
+  size_t arg_pos = arch.find (arg) + strlen (arg);
+  size_t end_pos = arch.find (" ", arg_pos);
+
+  std::string cpu = arch.substr (arg_pos, end_pos - arg_pos);
+  jit_target_set_arch (cpu);
+
+  jit_target_set_128bit_int_support (targetm.scalar_mode_supported_p (TImode));
+
+  if (TARGET_MMX)
+    jit_add_target_info ("target_feature", "mmx");
+  if (TARGET_SSE)
+    jit_add_target_info ("target_feature", "sse");
+  if (TARGET_SSE2)
+    jit_add_target_info ("target_feature", "sse2");
+  if (TARGET_SSE3)
+    jit_add_target_info ("target_feature", "sse3");
+  if (TARGET_SSSE3)
+    jit_add_target_info ("target_feature", "ssse3");
+  if (TARGET_SSE4_1)
+    jit_add_target_info ("target_feature", "sse4.1");
+  if (TARGET_SSE4_2)
+    jit_add_target_info ("target_feature", "sse4.2");
+  if (TARGET_AES)
+    jit_add_target_info ("target_feature", "aes");
+  if (TARGET_SHA)
+    jit_add_target_info ("target_feature", "sha");
+  if (TARGET_AVX)
+    jit_add_target_info ("target_feature", "avx");
+  if (TARGET_AVX2)
+    jit_add_target_info ("target_feature", "avx2");
+  if (TARGET_AVX512F)
+    jit_add_target_info ("target_feature", "avx512f");
+  if (TARGET_AVX512ER)
+    jit_add_target_info ("target_feature", "avx512er");
+  if (TARGET_AVX512CD)
+    jit_add_target_info ("target_feature", "avx512cd");
+  if (TARGET_AVX512PF)
+    jit_add_target_info ("target_feature", "avx512pf");
+  if (TARGET_AVX512DQ)
+    jit_add_target_info ("target_feature", "avx512dq");
+  if (TARGET_AVX512BW)
+    jit_add_target_info ("target_feature", "avx512bw");
+  if (TARGET_AVX512VL)
+    jit_add_target_info ("target_feature", "avx512vl");
+  if (TARGET_AVX512VBMI)
+    jit_add_target_info ("target_feature", "avx512vbmi");
+  if (TARGET_AVX512IFMA)
+    jit_add_target_info ("target_feature", "avx512ifma");
+  if (TARGET_AVX512VPOPCNTDQ)
+    jit_add_target_info ("target_feature", "avx512vpopcntdq");
+  if (TARGET_FMA)
+    jit_add_target_info ("target_feature", "fma");
+  if (TARGET_RTM)
+    jit_add_target_info ("target_feature", "rtm");
+  if (TARGET_SSE4A)
+    jit_add_target_info ("target_feature", "sse4a");
+  if (TARGET_BMI)
+  {
+    jit_add_target_info ("target_feature", "bmi1");
+    jit_add_target_info ("target_feature", "bmi");
+  }
+  if (TARGET_BMI2)
+    jit_add_target_info ("target_feature", "bmi2");
+  if (TARGET_LZCNT)
+    jit_add_target_info ("target_feature", "lzcnt");
+  if (TARGET_TBM)
+    jit_add_target_info ("target_feature", "tbm");
+  if (TARGET_POPCNT)
+    jit_add_target_info ("target_feature", "popcnt");
+  if (TARGET_RDRND)
+  {
+    jit_add_target_info ("target_feature", "rdrand");
+    jit_add_target_info ("target_feature", "rdrnd");
+  }
+  if (TARGET_F16C)
+    jit_add_target_info ("target_feature", "f16c");
+  if (TARGET_RDSEED)
+    jit_add_target_info ("target_feature", "rdseed");
+  if (TARGET_ADX)
+    jit_add_target_info ("target_feature", "adx");
+  if (TARGET_FXSR)
+    jit_add_target_info ("target_feature", "fxsr");
+  if (TARGET_XSAVE)
+    jit_add_target_info ("target_feature", "xsave");
+  if (TARGET_XSAVEOPT)
+    jit_add_target_info ("target_feature", "xsaveopt");
+  if (TARGET_XSAVEC)
+    jit_add_target_info ("target_feature", "xsavec");
+  if (TARGET_XSAVES)
+    jit_add_target_info ("target_feature", "xsaves");
+  if (TARGET_VPCLMULQDQ)
+  {
+    jit_add_target_info ("target_feature", "pclmulqdq");
+    jit_add_target_info ("target_feature", "vpclmulqdq");
+  }
+  if (TARGET_CMPXCHG16B)
+    jit_add_target_info ("target_feature", "cmpxchg16b");
+  if (TARGET_MOVBE)
+    jit_add_target_info ("target_feature", "movbe");
+  if (TARGET_AVX512VBMI2)
+    jit_add_target_info ("target_feature", "avx512vbmi2");
+  if (TARGET_PKU)
+    jit_add_target_info ("target_feature", "pku");
+  if (TARGET_AVX512VNNI)
+    jit_add_target_info ("target_feature", "avx512vnni");
+  if (TARGET_AVX512BF16)
+    jit_add_target_info ("target_feature", "avx512bf16");
+  if (TARGET_AVX512BITALG)
+    jit_add_target_info ("target_feature", "avx512bitalg");
+  if (TARGET_AVX512VP2INTERSECT)
+    jit_add_target_info ("target_feature", "avx512vp2intersect");
+  if (TARGET_PCLMUL)
+    jit_add_target_info ("target_feature", "pclmul");
+  if (TARGET_GFNI)
+    jit_add_target_info ("target_feature", "gfni");
+  if (TARGET_FMA4)
+    jit_add_target_info ("target_feature", "fma4");
+  if (TARGET_XOP)
+    jit_add_target_info ("target_feature", "xop");
+
+  if (TARGET_VAES)
+    jit_add_target_info ("target_feature", "vaes");
+  if (TARGET_LWP)
+    jit_add_target_info ("target_feature", "lwp");
+  if (TARGET_FSGSBASE)
+    jit_add_target_info ("target_feature", "fsgsbase");
+  if (TARGET_SHSTK)
+    jit_add_target_info ("target_feature", "shstk");
+  if (TARGET_PRFCHW)
+    jit_add_target_info ("target_feature", "prfchw");
+  if (TARGET_MWAITX)
+    jit_add_target_info ("target_feature", "mwaitx");
+  if (TARGET_CLZERO)
+    jit_add_target_info ("target_feature", "clzero");
+  if (TARGET_CLDEMOTE)
+    jit_add_target_info ("target_feature", "cldemote");
+  if (TARGET_PTWRITE)
+    jit_add_target_info ("target_feature", "ptwrite");
+  bool hasERMSB = ix86_arch == PROCESSOR_HASWELL
+    || ix86_arch == PROCESSOR_SKYLAKE || ix86_arch == PROCESSOR_SKYLAKE_AVX512
+    || ix86_arch == PROCESSOR_CANNONLAKE
+    || ix86_arch == PROCESSOR_ICELAKE_CLIENT
+    || ix86_arch == PROCESSOR_ICELAKE_SERVER
+    || ix86_arch == PROCESSOR_CASCADELAKE || ix86_arch == PROCESSOR_TIGERLAKE
+    || ix86_arch == PROCESSOR_COOPERLAKE;
+  if (hasERMSB)
+    jit_add_target_info ("target_feature", "ermsbd");
+}
diff --git a/gcc/config/i386/i386-jit.h b/gcc/config/i386/i386-jit.h
new file mode 100644
index 00000000000..4f05e88003f
--- /dev/null
+++ b/gcc/config/i386/i386-jit.h
@@ -0,0 +1,22 @@
+/* Definitions for the jit front end on the x86 architecture.
+   Copyright (C) 2023 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/>.  */
+
+/* In i386-jit.cc  */
+extern void ix86_jit_register_target_info (void);
+
+/* Target hooks for jit language.  */
+#define TARGET_JIT_REGISTER_CPU_TARGET_INFO ix86_jit_register_target_info
diff --git a/gcc/config/i386/t-i386 b/gcc/config/i386/t-i386
index f85817d698c..5a24ecea055 100644
--- a/gcc/config/i386/t-i386
+++ b/gcc/config/i386/t-i386
@@ -50,6 +50,10 @@ i386-rust.o: $(srcdir)/config/i386/i386-rust.cc
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+i386-jit.o: $(srcdir)/config/i386/i386-jit.cc
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 i386-options.o: $(srcdir)/config/i386/i386-options.cc
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gcc/config/linux-jit.cc b/gcc/config/linux-jit.cc
new file mode 100644
index 00000000000..e85a6f3be18
--- /dev/null
+++ b/gcc/config/linux-jit.cc
@@ -0,0 +1,36 @@
+/* Linux support needed only by jit front-end.
+   Copyright (C) 2023 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 "tm.h"
+#include "tm_jit.h"
+#include "jit/jit-target.h"
+#include "jit/jit-target-def.h"
+
+/* Implement TARGET_JIT_REGISTER_OS_TARGET_INFO for Linux targets.  */
+
+static void
+linux_jit_register_target_info (void)
+{
+}
+
+#undef TARGET_JIT_REGISTER_OS_TARGET_INFO
+#define TARGET_JIT_REGISTER_OS_TARGET_INFO linux_jit_register_target_info
+
+struct gcc_targetjitm targetjitm = TARGETJITM_INITIALIZER;
diff --git a/gcc/config/t-linux b/gcc/config/t-linux
index 96593fbf27f..14376825d79 100644
--- a/gcc/config/t-linux
+++ b/gcc/config/t-linux
@@ -27,3 +27,7 @@ linux-d.o: $(srcdir)/config/linux-d.cc
 linux-rust.o: $(srcdir)/config/linux-rust.cc
 	  $(COMPILE) $<
 	  $(POSTCOMPILE)
+
+linux-jit.o: $(srcdir)/config/linux-jit.cc
+	  $(COMPILE) $<
+	  $(POSTCOMPILE)
diff --git a/gcc/configure b/gcc/configure
index 0d818ae6850..e359d2fbdcc 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -647,6 +647,7 @@ GMPLIBS
 target_cpu_default
 rust_target_objs
 d_target_objs
+jit_target_objs
 fortran_target_objs
 cxx_target_objs
 c_target_objs
@@ -658,6 +659,8 @@ tm_rust_include_list
 tm_rust_file_list
 tm_d_include_list
 tm_d_file_list
+tm_jit_include_list
+tm_jit_file_list
 tm_p_include_list
 tm_p_file_list
 tm_defines
@@ -13629,6 +13632,17 @@ for f in $tm_rust_file; do
   esac
 done
 
+tm_jit_file_list=
+tm_jit_include_list=
+for f in $tm_jit_file; do
+  case $f in
+    * )
+       tm_jit_file_list="${tm_jit_file_list} \$(srcdir)/config/$f"
+       tm_jit_include_list="${tm_jit_include_list} config/$f"
+       ;;
+  esac
+done
+
 xm_file_list=
 xm_include_list=
 for f in $xm_file; do
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 764a33f0b04..f37409ba77d 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2451,6 +2451,17 @@ for f in $tm_rust_file; do
   esac
 done
 
+tm_jit_file_list=
+tm_jit_include_list=
+for f in $tm_jit_file; do
+  case $f in
+    * )
+       tm_jit_file_list="${tm_jit_file_list} \$(srcdir)/config/$f"
+       tm_jit_include_list="${tm_jit_include_list} config/$f"
+       ;;
+  esac
+done
+
 xm_file_list=
 xm_include_list=
 for f in $xm_file; do
@@ -7488,6 +7499,8 @@ AC_SUBST(tm_d_file_list)
 AC_SUBST(tm_d_include_list)
 AC_SUBST(tm_rust_file_list)
 AC_SUBST(tm_rust_include_list)
+AC_SUBST(tm_jit_file_list)
+AC_SUBST(tm_jit_include_list)
 AC_SUBST(xm_file_list)
 AC_SUBST(xm_include_list)
 AC_SUBST(xm_defines)
@@ -7497,6 +7510,7 @@ AC_SUBST(cxx_target_objs)
 AC_SUBST(fortran_target_objs)
 AC_SUBST(d_target_objs)
 AC_SUBST(rust_target_objs)
+AC_SUBST(jit_target_objs)
 AC_SUBST(target_cpu_default)
 
 AC_SUBST_FILE(language_hooks)
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index f7ac806ff15..5d8857ee07c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -124,6 +124,14 @@ If targets initialize @code{targetrustm} themselves, they should set
 @code{target_has_targetrustm=yes} in @file{config.gcc}; otherwise a
 default definition is used.
 
+Similarly, there is a @code{targetjitm} variable for hooks that are
+specific to the jit front end, documented as ``JIT Target Hook''.
+This is declared in @file{jit/jit-target.h}, the initializer
+@code{TARGETJITM_INITIALIZER} in @file{jit/jit-target-def.h}.  If targets
+initialize @code{targetjitm} themselves, they should set
+@code{target_has_targetjitm=yes} in @file{config.gcc}; otherwise a default
+definition is used.
+
 @node Driver
 @section Controlling the Compilation Driver, @file{gcc}
 @cindex driver
@@ -11006,6 +11014,24 @@ Similar to @code{TARGET_RUST_CPU_INFO}, but is used for configuration info
 relating to the target operating system.
 @end deftypefn
 
+@node JIT Language and ABI
+@section JIT ABI parameters
+@cindex parameters, jit abi
+
+@deftypefn {JIT Target Hook} void TARGET_JIT_REGISTER_CPU_TARGET_INFO (void)
+Register all target information keys relating to the target CPU using the
+function @code{jit_add_target_info_handlers}, which takes a
+@samp{struct jit_target_info_spec} (defined in @file{jit/jit-target.h}).  The
+keys added by this hook are made available at compile time by the
+@code{__traits(getTargetInfo)} extension, the result is an expression
+describing the requested target information.
+@end deftypefn
+
+@deftypefn {JIT Target Hook} void TARGET_JIT_REGISTER_OS_TARGET_INFO (void)
+Same as @code{TARGET_JIT_CPU_TARGET_INFO}, but is used for keys relating to
+the target operating system.
+@end deftypefn
+
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 141027e0bb4..7ab80266595 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -124,6 +124,14 @@ If targets initialize @code{targetrustm} themselves, they should set
 @code{target_has_targetrustm=yes} in @file{config.gcc}; otherwise a
 default definition is used.
 
+Similarly, there is a @code{targetjitm} variable for hooks that are
+specific to the jit front end, documented as ``JIT Target Hook''.
+This is declared in @file{jit/jit-target.h}, the initializer
+@code{TARGETJITM_INITIALIZER} in @file{jit/jit-target-def.h}.  If targets
+initialize @code{targetjitm} themselves, they should set
+@code{target_has_targetjitm=yes} in @file{config.gcc}; otherwise a default
+definition is used.
+
 @node Driver
 @section Controlling the Compilation Driver, @file{gcc}
 @cindex driver
@@ -7178,6 +7186,14 @@ floating-point support; they are not included in this mechanism.
 
 @hook TARGET_RUST_OS_INFO
 
+@node JIT Language and ABI
+@section JIT ABI parameters
+@cindex parameters, jit abi
+
+@hook TARGET_JIT_REGISTER_CPU_TARGET_INFO
+
+@hook TARGET_JIT_REGISTER_OS_TARGET_INFO
+
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/genhooks.cc b/gcc/genhooks.cc
index 49414eca531..7064d9659dd 100644
--- a/gcc/genhooks.cc
+++ b/gcc/genhooks.cc
@@ -36,6 +36,7 @@ static struct hook_desc hook_array[] = {
 #include "common/common-target.def"
 #include "d/d-target.def"
 #include "rust/rust-target.def"
+#include "jit/jit-target.def"
 #undef DEFHOOK
 };
 
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
index 3fd564a5932..19ef589e55c 100644
--- a/gcc/jit/Make-lang.in
+++ b/gcc/jit/Make-lang.in
@@ -120,7 +120,7 @@ jit.serial = $(LIBGCCJIT_FILENAME)
 # Tell GNU make to ignore these if they exist.
 .PHONY: jit
 
-jit_OBJS = attribs.o \
+JIT_OBJS = attribs.o \
 	jit/dummy-frontend.o \
 	jit/libgccjit.o \
 	jit/jit-logging.o \
@@ -129,13 +129,17 @@ jit_OBJS = attribs.o \
 	jit/jit-result.o \
 	jit/jit-tempdir.o \
 	jit/jit-builtins.o \
+	jit/jit-target.o \
 	jit/jit-spec.o \
 	gcc.o
 
 ifneq (,$(findstring mingw,$(target)))
-jit_OBJS += jit/jit-w32.o
+JIT_OBJS += jit/jit-w32.o
 endif
 
+# All language-specific object files for jit.
+jit_OBJS = $(JIT_OBJS) $(JIT_TARGET_OBJS)
+
 # Use strict warnings for this front end.
 jit-warn = $(STRICT_WARN)
 
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index ebede440ee4..fe73caa3982 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -378,3 +378,17 @@ alignment of a variable:
 --------------------
 ``LIBGCCJIT_ABI_25`` covers the addition of
 :func:`gcc_jit_type_get_restrict`
+
+.. _LIBGCCJIT_ABI_26:
+
+``LIBGCCJIT_ABI_26``
+--------------------
+``LIBGCCJIT_ABI_26`` covers the addition of functions to query the target
+information:
+
+  * :func:`gcc_jit_type_get_restrict`
+  * :func:`gcc_jit_context_get_target_info`
+  * :func:`gcc_jit_target_info_release`
+  * :func:`gcc_jit_target_info_cpu_supports`
+  * :func:`gcc_jit_target_info_arch`
+  * :func:`gcc_jit_target_info_supports_128bit_int`
diff --git a/gcc/jit/docs/topics/compilation.rst b/gcc/jit/docs/topics/compilation.rst
index 0911f108ba4..6db1de82c7d 100644
--- a/gcc/jit/docs/topics/compilation.rst
+++ b/gcc/jit/docs/topics/compilation.rst
@@ -199,3 +199,54 @@ The available kinds of output are:
 .. c:macro:: GCC_JIT_OUTPUT_KIND_EXECUTABLE
 
    Compile the context to an executable.
+
+
+Getting information about a target
+**********************************
+
+You can query the target information by using the following API:
+
+.. function:: gcc_jit_target_info * \
+              gcc_jit_context_get_target_info (gcc_jit_context *ctxt)
+
+   Compute the information about a target.
+
+   If the result is non-NULL, the caller becomes responsible for
+   calling :func:`gcc_jit_target_info_release` on it once they're done
+   with it.
+
+.. function:: void \
+              gcc_jit_target_info_release (gcc_jit_target_info *info)
+
+   This function releases all resources associated with the given target info.
+
+.. function:: int \
+              gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info,
+                                                const char *feature)
+
+   Check if the specified target INFO supports the cpu FEATURE.
+
+.. function:: const char * \
+              gcc_jit_target_info_arch (gcc_jit_target_info *info)
+
+   Get the architecture of the currently running CPU.
+
+.. function:: int \
+              gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info)
+
+   Check if the specified target INFO supports 128-bit integers.
+
+   The API entrypoints relating to the target info:
+
+      * :c:func:`gcc_jit_context_get_target_info`
+      * :c:func:`gcc_jit_target_info_release`
+      * :c:func:`gcc_jit_target_info_cpu_supports`
+      * :c:func:`gcc_jit_target_info_arch`
+      * :c:func:`gcc_jit_target_info_supports_128bit_int`
+
+   were added in :ref:`LIBGCCJIT_ABI_26`; you can test for their presence
+   using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 18cc4da25b8..bf53c039e85 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "jit-result.h"
 #include "jit-builtins.h"
 #include "jit-tempdir.h"
+#include "jit-target.h"
 
 #ifdef _WIN32
 #include "jit-w32.h"
@@ -3226,6 +3227,7 @@ replay ()
   JIT_LOG_SCOPE (get_logger ());
 
   init_types ();
+  jit_target_init ();
 
   /* Replay the recorded events:  */
   timevar_push (TV_JIT_REPLAY);
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index f9e29d0baec..afa6d281188 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -43,9 +43,10 @@ namespace playback {
 
 /* playback::context is an abstract base class.
 
-   The two concrete subclasses are:
+   The three concrete subclasses are:
    - playback::compile_to_memory
-   - playback::compile_to_file.  */
+   - playback::compile_to_file
+   - playback::get_target_info.  */
 
 class context : public log_user
 {
@@ -405,6 +406,18 @@ class compile_to_file : public context
   const char *m_output_path;
 };
 
+class get_target_info : public context
+{
+ public:
+  get_target_info (recording::context *ctxt) : context (ctxt)
+  {
+  }
+
+  void postprocess (const char *) final override
+  {
+  }
+};
+
 
 /* A temporary wrapper object.
    These objects are (mostly) only valid during replay.
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 9b5b8005ebe..94978170c10 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -1525,6 +1525,25 @@ recording::context::compile_to_file (enum gcc_jit_output_kind output_kind,
   replayer.compile ();
 }
 
+void
+recording::context::get_target_info ()
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  log_all_options ();
+
+  if (errors_occurred ())
+    return;
+
+  add_driver_option ("-fsyntax-only");
+
+  /* Set up a get_target_info playback context.  */
+  ::gcc::jit::playback::get_target_info replayer (this);
+
+  /* Use it.  */
+  replayer.compile ();
+}
+
 /* Format the given error using printf's conventions, print
    it to stderr, and add it to the context.  */
 
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 4a8082991fb..a090c85b19e 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -283,6 +283,9 @@ public:
   compile_to_file (enum gcc_jit_output_kind output_kind,
 		   const char *output_path);
 
+  void
+  get_target_info ();
+
   void
   add_error (location *loc, const char *fmt, ...)
       GNU_PRINTF(3, 4);
diff --git a/gcc/jit/jit-target-def.h b/gcc/jit/jit-target-def.h
new file mode 100644
index 00000000000..dcb342fafe7
--- /dev/null
+++ b/gcc/jit/jit-target-def.h
@@ -0,0 +1,20 @@
+/* jit-target-def.h -- Default initializers for jit target hooks.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "jit/jit-target-hooks-def.h"
+#include "tree.h"
+#include "hooks.h"
diff --git a/gcc/jit/jit-target.cc b/gcc/jit/jit-target.cc
new file mode 100644
index 00000000000..e8ac847d3df
--- /dev/null
+++ b/gcc/jit/jit-target.cc
@@ -0,0 +1,89 @@
+/* jit-target.cc -- Target interface for the jit front end.
+   Copyright (C) 2023 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 "tree.h"
+#include "memmodel.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stor-layout.h"
+#include "tm.h"
+#include "tm_p.h"
+#include "target.h"
+#include "calls.h"
+
+#include "jit-target.h"
+
+#include <algorithm>
+
+static target_info jit_target_info;
+
+/* Initialize all variables of the Target structure.  */
+
+void
+jit_target_init ()
+{
+  /* Initialize target info tables, the keys required by the language are added
+     last, so that the OS and CPU handlers can override.  */
+  targetjitm.jit_register_cpu_target_info ();
+  targetjitm.jit_register_os_target_info ();
+}
+
+/* Add all target info in HANDLERS to JIT_TARGET_INFO for use by
+   jit_has_target_value ().  */
+
+void
+jit_add_target_info (const char *key, const char *value)
+{
+  if (jit_target_info.m_info.find (key) == jit_target_info.m_info.end ())
+    jit_target_info.m_info.insert ({key, {value}});
+  else
+    jit_target_info.m_info[key].insert (value);
+}
+
+void
+jit_target_set_arch (std::string const& arch)
+{
+  jit_target_info.m_arch = arch;
+}
+
+void
+jit_target_set_128bit_int_support (bool support)
+{
+  jit_target_info.m_supports_128bit_int = support;
+}
+
+target_info *
+jit_get_target_info ()
+{
+  target_info *info = new target_info {jit_target_info};
+  jit_target_info = target_info{};
+  return info;
+}
+
+bool
+target_info::has_target_value (const char *key, const char *value)
+{
+  if (m_info.find (key) == m_info.end ())
+    return false;
+
+  auto& set = m_info[key];
+  return set.find (value) != set.end ();
+}
diff --git a/gcc/jit/jit-target.def b/gcc/jit/jit-target.def
new file mode 100644
index 00000000000..de0d717b365
--- /dev/null
+++ b/gcc/jit/jit-target.def
@@ -0,0 +1,52 @@
+/* jit-target.def -- Target hook definitions for the jit front end.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* See target-hooks-macros.h for details of macros that should be
+   provided by the including file, and how to use them here.  */
+
+#include "target-hooks-macros.h"
+
+#undef HOOK_TYPE
+#define HOOK_TYPE "JIT Target Hook"
+
+HOOK_VECTOR (TARGETJITM_INITIALIZER, gcc_targetjitm)
+
+#undef HOOK_PREFIX
+#define HOOK_PREFIX "TARGET_"
+
+/* getTargetInfo keys relating to the target CPU.  */
+DEFHOOK
+(jit_register_cpu_target_info,
+ "Register all target information keys relating to the target CPU using the\n\
+function @code{jit_add_target_info_handlers}, which takes a\n\
+@samp{struct jit_target_info_spec} (defined in @file{jit/jit-target.h}).  The\n\
+keys added by this hook are made available at compile time by the\n\
+@code{__traits(getTargetInfo)} extension, the result is an expression\n\
+describing the requested target information.",
+ void, (void),
+ hook_void_void)
+
+/* getTargetInfo keys relating to the target OS.  */
+DEFHOOK
+(jit_register_os_target_info,
+ "Same as @code{TARGET_JIT_CPU_TARGET_INFO}, but is used for keys relating to\n\
+the target operating system.",
+ void, (void),
+ hook_void_void)
+
+/* Close the 'struct gcc_targetdm' definition.  */
+HOOK_VECTOR_END (C90_EMPTY_HACK)
diff --git a/gcc/jit/jit-target.h b/gcc/jit/jit-target.h
new file mode 100644
index 00000000000..6443cd71025
--- /dev/null
+++ b/gcc/jit/jit-target.h
@@ -0,0 +1,73 @@
+/* jit-target.h -- Data structure definitions for target-specific jit behavior.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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 this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_JIT_TARGET_H
+#define GCC_JIT_TARGET_H
+
+#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
+#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS;
+#define DEFHOOK_UNDOC DEFHOOK
+#define HOOKSTRUCT(FRAGMENT) FRAGMENT
+
+#include "jit-target.def"
+
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+static size_t hash_cstr (const char *s)
+{
+  const size_t seed = 0;
+  return std::_Hash_bytes (s, std::strlen (s), seed);
+}
+
+struct CStringHash {
+  size_t operator() (const char* const &string) const {
+    auto res = hash_cstr (string);
+    return res;
+  }
+};
+
+struct CStringEqual {
+  bool operator() (const char* const &string1,
+		   const char* const &string2) const {
+      return strcmp (string1, string2) == 0;
+  }
+};
+
+struct target_info {
+  public:
+    bool has_target_value (const char *key, const char *value);
+
+    std::unordered_map<const char *,
+		       std::unordered_set<const char *, CStringHash,
+					  CStringEqual>,
+		       CStringHash, CStringEqual> m_info;
+    std::string m_arch;
+    bool m_supports_128bit_int = false;
+};
+
+/* Each target can provide their own.  */
+extern struct gcc_targetjitm targetjitm;
+
+extern void jit_target_init ();
+extern void jit_target_set_arch (std::string const& arch);
+extern void jit_target_set_128bit_int_support (bool support);
+extern void jit_add_target_info (const char *key, const char *value);
+extern target_info * jit_get_target_info ();
+
+#endif /* GCC_JIT_TARGET_H  */
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 0451b4df7f9..15ba3acc95c 100644
--- a/gcc/jit/libgccjit.cc
+++ b/gcc/jit/libgccjit.cc
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "libgccjit.h"
 #include "jit-recording.h"
 #include "jit-result.h"
+#include "jit-target.h"
 
 /* The opaque types used by the public API are actually subclasses
    of the gcc::jit::recording classes.  */
@@ -44,6 +45,10 @@ struct gcc_jit_result : public gcc::jit::result
 {
 };
 
+struct gcc_jit_target_info : public target_info
+{
+};
+
 struct gcc_jit_object : public gcc::jit::recording::memento
 {
 };
@@ -3679,6 +3684,44 @@ gcc_jit_context_compile_to_file (gcc_jit_context *ctxt,
   ctxt->compile_to_file (output_kind, output_path);
 }
 
+gcc_jit_target_info *
+gcc_jit_context_get_target_info (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  ctxt->log ("get_target_info of ctxt: %p", (void *)ctxt);
+
+  ctxt->get_target_info ();
+
+  return (gcc_jit_target_info*) jit_get_target_info ();
+}
+
+void
+gcc_jit_target_info_release (gcc_jit_target_info *info)
+{
+  RETURN_IF_FAIL (info, NULL, NULL, "NULL info");
+  delete info;
+}
+
+int
+gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info,
+				  const char *feature)
+{
+  return info->has_target_value ("target_feature", feature);
+}
+
+const char *
+gcc_jit_target_info_arch (gcc_jit_target_info *info)
+{
+  return info->m_arch.c_str ();
+}
+
+int
+gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info)
+{
+  return info->m_supports_128bit_int;
+}
 
 /* Public entrypoint.  See description in libgccjit.h.
 
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 749f6c24177..a289862311b 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -52,6 +52,9 @@ typedef struct gcc_jit_context gcc_jit_context;
 /* A gcc_jit_result encapsulates the result of an in-memory compilation.  */
 typedef struct gcc_jit_result gcc_jit_result;
 
+/* A gcc_jit_target_info encapsulates the target info.  */
+typedef struct gcc_jit_target_info gcc_jit_target_info;
+
 /* An object created within a context.  Such objects are automatically
    cleaned up when the context is released.
 
@@ -1999,6 +2002,63 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type);
 extern gcc_jit_type *
 gcc_jit_type_unqualified (gcc_jit_type *type);
 
+/* Create a gcc_jit_target_info instance.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
+*/
+
+extern gcc_jit_target_info *
+gcc_jit_context_get_target_info (gcc_jit_context *ctxt);
+
+/* Release a gcc_jit_target_info instance.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
+*/
+
+extern void
+gcc_jit_target_info_release (gcc_jit_target_info *info);
+
+/* Returns non-zero if FEATURE is supported by the specified target.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
+*/
+
+extern int
+gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info,
+				  const char *feature);
+
+/* Returns the ARCH of the currently running CPU.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
+*/
+
+extern const char *
+gcc_jit_target_info_arch (gcc_jit_target_info *info);
+
+/* Returns non-zero if the target natively supports 128-bit integers.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
+*/
+
+extern int
+gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info);
+
+/* The target info API was added in LIBGCCJIT_ABI_26; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_TARGET_INFO_API
+*/
+#define LIBGCCJIT_HAVE_TARGET_INFO_API
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 8b90a0e2ff3..30f08ce67d7 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -276,3 +276,12 @@ LIBGCCJIT_ABI_25 {
   global:
     gcc_jit_type_get_restrict;
 } LIBGCCJIT_ABI_24;
+
+LIBGCCJIT_ABI_26 {
+  global:
+    gcc_jit_context_get_target_info;
+    gcc_jit_target_info_release;
+    gcc_jit_target_info_cpu_supports;
+    gcc_jit_target_info_arch;
+    gcc_jit_target_info_supports_128bit_int;
+} LIBGCCJIT_ABI_25;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index e762563f9bd..f0f7356d687 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -322,6 +322,9 @@
 /* test-setting-alignment.c: This can't be in the testcases array as it
    is target-specific.  */
 
+/* test-target-info.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-info.c b/gcc/testsuite/jit.dg/test-target-info.c
new file mode 100644
index 00000000000..db5591edcbd
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-target-info.c
@@ -0,0 +1,63 @@
+/* { 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)
+{
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  /*  This is the same as the main provided by harness.h, but calls gcc_jit_context_get_target_info.  */
+  gcc_jit_context *ctxt;
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fail ("gcc_jit_context_acquire failed");
+      return -1;
+    }
+  gcc_jit_target_info* info = gcc_jit_context_get_target_info (ctxt);
+
+  int sse2_supported = gcc_jit_target_info_cpu_supports (info, "sse2");
+  CHECK_VALUE (sse2_supported, 1);
+
+  const char *arch = gcc_jit_target_info_arch (info);
+  // TODO: not sure what value to check here.
+  CHECK_STRING_VALUE (arch, "znver2");
+
+  int supports_128bit_int = gcc_jit_target_info_supports_128bit_int (info);
+  CHECK_VALUE (supports_128bit_int, 1);
+  gcc_jit_target_info_release (info);
+  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;
+}
-- 
2.42.0


^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-04-26 13:51 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-09 22:27 [PATCH] libgccjit: Add ability to get CPU features Antoni Boucher
2023-11-09 23:04 ` David Malcolm
2023-11-10  0:33   ` Antoni Boucher
2023-11-30 22:11     ` Antoni Boucher
2024-03-05 15:09     ` Frontend access to target features (was Re: [PATCH] libgccjit: Add ability to get CPU features) David Malcolm
2024-03-10 11:05       ` Iain Buclaw
2024-03-18 11:39         ` Antoni Boucher
2024-03-19 11:03       ` Arthur Cohen
2024-04-01 12:20         ` Antoni Boucher
2024-04-09 13:21           ` Antoni Boucher
2024-04-19 12:34             ` Antoni Boucher
2024-04-26 13:51               ` Antoni Boucher
2023-12-13 19:56   ` [PATCH] libgccjit: Add ability to get CPU features Antoni Boucher
2024-01-10 23:18     ` Antoni Boucher
2024-01-11 18:49   ` Antoni Boucher
2024-01-19 12:53   ` Antoni Boucher
2024-01-20 14:50   ` Antoni Boucher
2024-01-30 15:50     ` Antoni Boucher
2024-02-06 12:54       ` Antoni Boucher
2024-02-13 18:37         ` Antoni Boucher
2024-02-29 15:34           ` Antoni Boucher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).