diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000000..5fab7cf772c
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,32 @@
+name: CI
+
+on:
+ - push
+ - pull_request
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install mpfr
+ run: sudo apt-get install gcc-10 libmpfr-dev libmpc-dev
+
+ - name: Build libgccjit
+ run: |
+ cd ..
+ ls
+ mkdir build install
+ cd build
+ ../gcc/configure --enable-host-shared --enable-languages=jit,c++ --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install
+ make -j4
+
+ - uses: actions/upload-artifact@v2
+ with:
+ name: libgccjit.so
+ path: /home/runner/work/gcc/build/gcc/libgccjit.so
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 6aed2cda3ca..4c092094343 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -574,6 +574,8 @@ tm_p_file_list=@tm_p_file_list@
tm_p_include_list=@tm_p_include_list@
tm_d_file_list=@tm_d_file_list@
tm_d_include_list=@tm_d_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@
@@ -868,6 +870,7 @@ CONFIG_H = config.h $(host_xm_file_list)
TCONFIG_H = tconfig.h $(xm_file_list)
TM_P_H = tm_p.h $(tm_p_file_list)
TM_D_H = tm_d.h $(tm_d_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)
@@ -926,10 +929,12 @@ TARGET_DEF = target.def target-hooks-macros.h target-insns.def
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
+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)
+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)
@@ -1230,6 +1235,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@
@@ -1947,6 +1955,7 @@ tconfig.h: cs-tconfig.h ; @true
tm.h: cs-tm.h ; @true
tm_p.h: cs-tm_p.h ; @true
tm_d.h: cs-tm_d.h ; @true
+tm_jit.h: cs-tm_jit.h ; @true
cs-config.h: Makefile
TARGET_CPU_DEFAULT="" \
@@ -1978,6 +1987,11 @@ cs-tm_d.h: Makefile
HEADERS="$(tm_d_include_list)" DEFINES="" \
$(SHELL) $(srcdir)/mkconfig.sh tm_d.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
@@ -2619,6 +2633,15 @@ s-d-target-hooks-def-h: build/genhooks$(build_exeext)
d/d-target-hooks-def.h
$(STAMP) s-d-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
@@ -2794,7 +2817,7 @@ s-gtype: $(EXTRA_GTYPE_DEPS) build/gengtype$(build_exeext) \
-r gtype.state
$(STAMP) s-gtype
-generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \
+generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_JIT_H) $(TM_H) multilib.h \
$(simple_generated_h) specs.h \
tree-check.h genrtl.h insn-modes.h insn-modes-inline.h \
tm-preds.h tm-constrs.h \
@@ -2803,7 +2826,7 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \
common/common-target-hooks-def.h pass-instances.def \
gimple-match.cc generic-match.cc \
c-family/c-target-hooks-def.h d/d-target-hooks-def.h \
- case-cfn-macros.h \
+ jit/jit-target-hooks-def.h case-cfn-macros.h \
cfn-operators.pd omp-device-properties.h
#
@@ -2937,7 +2960,7 @@ 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) $(BCONFIG_H) $(SYSTEM_H) errors.h
+ $(COMMON_TARGET_DEF) $(D_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) \
diff --git a/gcc/config.gcc b/gcc/config.gcc
index c4633e869ac..6a0fc540bcb 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -146,6 +146,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.
#
@@ -201,6 +204,9 @@
#
# target_has_targetdm Set to yes or no depending on whether the target
# has its own definition of targetdm.
+#
+# target_has_targetjitm Set to yes or no depending on whether the target
+# has its own definition of targetdm.
out_file=
common_out_file=
@@ -217,10 +223,12 @@ extra_options=
c_target_objs=
cxx_target_objs=
d_target_objs=
+jit_target_objs=
fortran_target_objs=
target_has_targetcm=no
target_has_targetm_common=yes
target_has_targetdm=no
+target_has_targetjitm=no
tm_defines=
xm_defines=
# Set this to force installation and use of collect2.
@@ -338,6 +346,7 @@ aarch64*-*-*)
c_target_objs="aarch64-c.o"
cxx_target_objs="aarch64-c.o"
d_target_objs="aarch64-d.o"
+ #jit_target_objs="aarch64-jit.o"
extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o aarch64-cc-fusion.o"
target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.cc \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc"
target_has_targetm_common=yes
@@ -368,6 +377,7 @@ arm*-*-*)
c_target_objs="arm-c.o"
cxx_target_objs="arm-c.o"
d_target_objs="arm-d.o"
+ #jit_target_objs="arm-jit.o"
extra_options="${extra_options} arm/arm-tables.opt"
target_gtfiles="\$(srcdir)/config/arm/arm-builtins.cc \$(srcdir)/config/arm/arm-mve-builtins.h \$(srcdir)/config/arm/arm-mve-builtins.cc"
;;
@@ -401,6 +411,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"
@@ -462,6 +473,7 @@ microblaze*-*-*)
mips*-*-*)
cpu_type=mips
d_target_objs="mips-d.o"
+ #jit_target_objs="mips-jit.o"
extra_headers="loongson.h loongson-mmiintrin.h msa.h"
extra_objs="frame-header-opt.o"
extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt"
@@ -532,6 +544,7 @@ riscv*)
extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o"
extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
d_target_objs="riscv-d.o"
+ #jit_target_objs="riscv-jit.o"
extra_headers="riscv_vector.h"
target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc"
target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.h"
@@ -548,11 +561,13 @@ sparc*-*-*)
c_target_objs="sparc-c.o"
cxx_target_objs="sparc-c.o"
d_target_objs="sparc-d.o"
+ #jit_target_objs="sparc-jit.o"
extra_headers="visintrin.h"
;;
s390*-*-*)
cpu_type=s390
d_target_objs="s390-d.o"
+ #jit_target_objs="s390-jit.o"
extra_options="${extra_options} fused-madd.opt"
extra_headers="s390intrin.h htmintrin.h htmxlintrin.h vecintrin.h"
;;
@@ -588,6 +603,12 @@ then
tm_d_file="${tm_d_file} ${cpu_type}/${cpu_type}-d.h"
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
@@ -754,9 +775,11 @@ case ${target} in
c_target_objs="${c_target_objs} darwin-c.o"
cxx_target_objs="${cxx_target_objs} darwin-c.o"
d_target_objs="${d_target_objs} darwin-d.o"
+ #jit_target_objs="${jit_target_objs} darwin-jit.o"
fortran_target_objs="darwin-f.o"
target_has_targetcm=yes
target_has_targetdm=yes
+ #target_has_targetjitm=yes
extra_objs="${extra_objs} darwin.o"
extra_gcc_objs="darwin-driver.o"
default_use_cxa_atexit=yes
@@ -785,8 +808,10 @@ case ${target} in
default_use_cxa_atexit=yes
use_gcc_stdint=wrap
d_target_objs="${d_target_objs} dragonfly-d.o"
+ #jit_target_objs="${jit_target_objs} dragonfly-jit.o"
tmake_file="${tmake_file} t-dragonfly"
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
*-*-freebsd*)
# This is the generic ELF configuration of FreeBSD. Later
@@ -836,8 +861,10 @@ case ${target} in
esac
use_gcc_stdint=wrap
d_target_objs="${d_target_objs} freebsd-d.o"
+ #jit_target_objs="${jit_target_objs} freebsd-jit.o"
tmake_file="${tmake_file} t-freebsd"
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
*-*-fuchsia*)
native_system_header_dir=/include
@@ -910,19 +937,27 @@ 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
+ target_has_targetjitm=yes
;;
*-*-kfreebsd*-gnu)
d_target_objs="${d_target_objs} kfreebsd-d.o"
+ #jit_target_objs="${jit_target_objs} kfreebsd-jit.o"
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
*-*-kopensolaris*-gnu)
d_target_objs="${d_target_objs} kopensolaris-d.o"
+ #jit_target_objs="${jit_target_objs} kopensolaris-jit.o"
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
*-*-gnu*)
d_target_objs="${d_target_objs} gnu-d.o"
+ #jit_target_objs="${jit_target_objs} gnu-jit.o"
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
esac
;;
@@ -931,6 +966,7 @@ case ${target} in
tmake_file="t-netbsd t-slibgcc"
extra_objs="${extra_objs} netbsd.o"
d_target_objs="${d_target_objs} netbsd-d.o"
+ #jit_target_objs="${jit_target_objs} netbsd-jit.o"
gas=yes
gnu_ld=yes
use_gcc_stdint=wrap
@@ -940,6 +976,7 @@ case ${target} in
nbsd_tm_file="netbsd.h netbsd-stdint.h netbsd-elf.h"
default_use_cxa_atexit=yes
target_has_targetdm=yes
+ #target_has_targetjitm=yes
case ${target} in
arm*-* | i[34567]86-* | powerpc*-* | sparc*-* | x86_64-*)
default_gnu_indirect_function=yes
@@ -959,7 +996,9 @@ case ${target} in
;;
esac
d_target_objs="${d_target_objs} openbsd-d.o"
+ #jit_target_objs="${jit_target_objs} openbsd-jit.o"
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
*-*-phoenix*)
gas=yes
@@ -1016,6 +1055,7 @@ case ${target} in
c_target_objs="${c_target_objs} sol2-c.o"
cxx_target_objs="${cxx_target_objs} sol2-c.o sol2-cxx.o"
d_target_objs="${d_target_objs} sol2-d.o"
+ #jit_target_objs="${jit_target_objs} sol2-jit.o"
extra_objs="${extra_objs} sol2.o sol2-stubs.o"
extra_options="${extra_options} sol2.opt"
case ${enable_threads}:${have_pthread_h}:${have_thread_h} in
@@ -1024,6 +1064,7 @@ case ${target} in
;;
esac
target_has_targetdm=yes
+ #target_has_targetjitm=yes
;;
*-*-*vms*)
extra_options="${extra_options} vms/vms.opt"
@@ -1760,6 +1801,7 @@ hppa*64*-*-linux*)
pa/pa64-linux.h"
tmake_file="${tmake_file} pa/t-pa pa/t-linux"
d_target_objs="${d_target_objs} pa-d.o"
+ #jit_target_objs="${jit_target_objs} pa-jit.o"
gas=yes gnu_ld=yes
;;
hppa*-*-linux*)
@@ -1768,6 +1810,7 @@ hppa*-*-linux*)
pa/pa32-regs.h pa/pa32-linux.h"
tmake_file="${tmake_file} pa/t-pa pa/t-linux"
d_target_objs="${d_target_objs} pa-d.o"
+ #jit_target_objs="${jit_target_objs} pa-jit.o"
;;
hppa*-*-openbsd*)
target_cpu_default="MASK_PA_11"
@@ -1776,6 +1819,7 @@ hppa*-*-openbsd*)
extra_options="${extra_options} openbsd.opt"
tmake_file="pa/t-pa"
d_target_objs="${d_target_objs} pa-d.o"
+ #jit_target_objs="${jit_target_objs} pa-jit.o"
gas=yes
gnu_ld=yes
;;
@@ -1813,6 +1857,7 @@ hppa*64*-*-hpux11*)
pa/pa-hpux1010.opt pa/pa64-hpux.opt hpux11.opt"
tmake_file="pa/t-pa t-slibgcc"
d_target_objs="${d_target_objs} pa-d.o"
+ #jit_target_objs="${jit_target_objs} pa-jit.o"
case x${enable_threads} in
x | xyes | xposix )
thread_file=posix
@@ -2086,7 +2131,9 @@ i[34567]86-*-cygwin*)
c_target_objs="${c_target_objs} msformat-c.o"
cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
d_target_objs="${d_target_objs} cygwin-d.o"
+ #jit_target_objs="${jit_target_objs} cygwin-jit.o"
target_has_targetdm="yes"
+ #target_has_targetjitm=yes
if test x$enable_threads = xyes; then
thread_file='posix'
fi
@@ -2104,7 +2151,9 @@ x86_64-*-cygwin*)
c_target_objs="${c_target_objs} msformat-c.o"
cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
d_target_objs="${d_target_objs} cygwin-d.o"
+ #jit_target_objs="${jit_target_objs} cygwin-jit.o"
target_has_targetdm="yes"
+ #target_has_targetjitm=yes
if test x$enable_threads = xyes; then
thread_file='posix'
fi
@@ -2118,8 +2167,10 @@ i[34567]86-*-mingw* | x86_64-*-mingw*)
c_target_objs="${c_target_objs} winnt-c.o"
cxx_target_objs="${cxx_target_objs} winnt-c.o"
d_target_objs="${d_target_objs} winnt-d.o"
+ #jit_target_objs="${jit_target_objs} winnt-jit.o"
target_has_targetcm="yes"
target_has_targetdm="yes"
+ #target_has_targetjitm=yes
case ${target} in
x86_64-*-* | *-w64-*)
need_64bit_isa=yes
@@ -3582,6 +3633,10 @@ if [ "$target_has_targetdm" = "no" ]; then
d_target_objs="$d_target_objs default-d.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
@@ -5752,6 +5807,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..6bee98a79ce
--- /dev/null
+++ b/gcc/config/default-jit.cc
@@ -0,0 +1,28 @@
+/* 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
+. */
+
+#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_targetdm targetjitm = TARGETJITM_INITIALIZER;
diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc
index 01192ef4259..37df854ba51 100644
--- a/gcc/config/i386/i386-builtins.cc
+++ b/gcc/config/i386/i386-builtins.cc
@@ -226,6 +226,22 @@ static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX];
struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX];
+static void
+clear_builtin_types (void)
+{
+ for (int i = 0 ; i < IX86_BT_LAST_CPTR + 1 ; i++)
+ ix86_builtin_type_tab[i] = NULL;
+
+ for (int i = 0 ; i < IX86_BUILTIN_MAX ; i++)
+ {
+ ix86_builtins[i] = NULL;
+ ix86_builtins_isa[i].set_and_not_built_p = true;
+ }
+
+ for (int i = 0 ; i < IX86_BT_LAST_ALIAS + 1 ; i++)
+ ix86_builtin_func_type_tab[i] = NULL;
+}
+
tree get_ix86_builtin (enum ix86_builtins c)
{
return ix86_builtins[c];
@@ -1443,6 +1459,8 @@ ix86_init_builtins (void)
{
tree ftype, decl;
+ clear_builtin_types ();
+
ix86_init_builtin_types ();
/* Builtins to get CPU type and features. */
diff --git a/gcc/config/i386/i386-jit.cc b/gcc/config/i386/i386-jit.cc
new file mode 100644
index 00000000000..3014baefc30
--- /dev/null
+++ b/gcc/config/i386/i386-jit.cc
@@ -0,0 +1,216 @@
+/* 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
+. */
+
+#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_CPU_VERSIONS for x86 targets. */
+
+void
+ix86_jit_target_versions (void)
+{
+ if (TARGET_64BIT)
+ {
+ jit_add_target_info ("target_arch", "x86_64");
+
+ // TODO
+ /*if (TARGET_X32)
+ jit_add_target_info ("target_arch", "D_X32");*/
+ }
+ else
+ jit_add_target_info ("target_arch", "x86");
+}
+
+/* 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 *arch = host_detect_local_cpu (2, params);
+
+ const char* arg = "-march=";
+ const char* arg_pos = strstr(arch, arg);
+ const char* arg_value = arg_pos + strlen(arg);
+ const char* arg_value_end = strchr(arg_value, ' ');
+
+ size_t len = arg_value_end - arg_value;
+ char *cpu = new char[len];
+ strncpy(cpu, arg_value, len);
+ cpu[len] = '\0';
+ jit_target_set_arch (cpu);
+
+ jit_target_set_128bit_int_support (targetm.scalar_mode_supported_p (TImode));
+
+ free (const_cast (arch));
+
+ 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");
+
+ // this is only enabled by choice in llvm, never by default - TODO determine if gcc enables it
+ // jit_add_target_info("target_feature", "sse-unaligned-mem");
+
+ 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_SAHF) // would this be better as TARGET_USE_SAHF?
+ jit_add_target_info("target_feature", "sahf");
+ 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..8cfccba405f
--- /dev/null
+++ b/gcc/config/i386/i386-jit.h
@@ -0,0 +1,26 @@
+/* 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
+. */
+
+/* In i386-jit.cc */
+extern void ix86_jit_target_versions (void);
+extern void ix86_jit_register_target_info (void);
+extern bool ix86_jit_has_stdcall_convention (unsigned int *, unsigned int *);
+
+/* Target hooks for jit language. */
+#define TARGET_JIT_CPU_VERSIONS ix86_jit_target_versions
+#define TARGET_JIT_REGISTER_CPU_TARGET_INFO ix86_jit_register_target_info
+#define TARGET_JIT_HAS_STDCALL_CONVENTION ix86_jit_has_stdcall_convention
diff --git a/gcc/config/i386/t-i386 b/gcc/config/i386/t-i386
index ffdbbdfe8ce..8421b4dba42 100644
--- a/gcc/config/i386/t-i386
+++ b/gcc/config/i386/t-i386
@@ -46,6 +46,10 @@ i386-d.o: $(srcdir)/config/i386/i386-d.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..20f0d8b4c65
--- /dev/null
+++ b/gcc/config/linux-jit.cc
@@ -0,0 +1,48 @@
+/* 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
+. */
+
+#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"
+
+// TODO: remove this hook?
+/* Implement TARGET_JIT_OS_VERSIONS for Linux targets. */
+
+static void
+linux_jit_os_builtins (void)
+{
+}
+
+// TODO: remove this hook?
+/* Implement TARGET_JIT_REGISTER_OS_TARGET_INFO for Linux targets. */
+
+static void
+linux_jit_register_target_info (void)
+{
+}
+
+#undef TARGET_JIT_OS_VERSIONS
+#define TARGET_JIT_OS_VERSIONS linux_jit_os_builtins
+
+#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 03966d5ce96..0be3fb24404 100644
--- a/gcc/config/t-linux
+++ b/gcc/config/t-linux
@@ -23,3 +23,7 @@ linux.o: $(srcdir)/config/linux.cc
linux-d.o: $(srcdir)/config/linux-d.cc
$(COMPILE) $<
$(POSTCOMPILE)
+
+linux-jit.o: $(srcdir)/config/linux-jit.cc
+ $(COMPILE) $<
+ $(POSTCOMPILE)
diff --git a/gcc/configure b/gcc/configure
index 254f9b6c943..dbbc21381d4 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -645,6 +645,7 @@ GMPINC
GMPLIBS
target_cpu_default
d_target_objs
+jit_target_objs
fortran_target_objs
cxx_target_objs
c_target_objs
@@ -654,6 +655,8 @@ xm_include_list
xm_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
@@ -13506,6 +13509,17 @@ for f in $tm_d_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 62bc908b991..0513895f7d9 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2371,6 +2371,17 @@ for f in $tm_d_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
@@ -7328,6 +7339,8 @@ AC_SUBST(tm_p_file_list)
AC_SUBST(tm_p_include_list)
AC_SUBST(tm_d_file_list)
AC_SUBST(tm_d_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)
@@ -7336,6 +7349,7 @@ AC_SUBST(c_target_objs)
AC_SUBST(cxx_target_objs)
AC_SUBST(fortran_target_objs)
AC_SUBST(d_target_objs)
+AC_SUBST(jit_target_objs)
AC_SUBST(target_cpu_default)
AC_SUBST_FILE(language_hooks)
diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc
index 65b95fee243..e66cd30c1fe 100644
--- a/gcc/dwarf2asm.cc
+++ b/gcc/dwarf2asm.cc
@@ -1159,4 +1159,14 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public,
va_end (ap);
}
+void dwarf2asm_cc_finalize (void)
+{
+ if (indirect_pool)
+ {
+ indirect_pool->empty();
+ indirect_pool = NULL;
+ }
+ dw2_const_labelno = 0;
+}
+
#include "gt-dwarf2asm.h"
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index 37a0a05e5bb..80695b3c6c8 100644
--- a/gcc/dwarf2asm.h
+++ b/gcc/dwarf2asm.h
@@ -86,6 +86,8 @@ extern const char *eh_data_format_name (int);
extern rtx dw2_force_const_mem (rtx, bool);
extern void dw2_output_indirect_constants (void);
+void dwarf2asm_cc_finalize (void);
+
/* These are currently unused. */
#if 0
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 1f39df3b1e2..61b711d4a52 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -1003,6 +1003,9 @@ dwarf2out_do_cfi_startproc (bool second)
if (targetm.asm_out.make_eh_symbol_indirect != NULL)
ref = targetm.asm_out.make_eh_symbol_indirect (ref, true);
else
+ // TODO: HERE: should not insert multiple times the same personality function.
+ // If we don't, we segfault later, possibly because we don't generate the info for the duplicates.
+ // I'm not sure why it's attempting to insert multiple times the same personality function.
ref = dw2_force_const_mem (ref, true);
}
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index a11f72f606b..61603c37230 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -6191,8 +6191,13 @@ init_emit_once (void)
/* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case
tries to use these variables. */
for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
- const_int_rtx[i + MAX_SAVED_CONST_INT] =
- gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i);
+ {
+ // Do not initialize twice the constants because there are used elsewhere
+ // and libgccjit execute this function twice.
+ if (const_int_rtx[i + MAX_SAVED_CONST_INT] == NULL)
+ const_int_rtx[i + MAX_SAVED_CONST_INT] =
+ gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i);
+ }
if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
&& STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 15be1c8db99..7fa2c114cb2 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -13365,6 +13365,7 @@ const_vector_from_tree (tree exp)
tree
build_personality_function (const char *lang)
{
+ // TODO: rewrite by calling build_personality_function_with_name.
const char *unwind_and_version;
tree decl, type;
char *name;
@@ -13406,6 +13407,28 @@ build_personality_function (const char *lang)
return decl;
}
+tree
+build_personality_function_with_name (const char *name)
+{
+ tree decl, type;
+
+ type = build_function_type_list (unsigned_type_node,
+ integer_type_node, integer_type_node,
+ long_long_unsigned_type_node,
+ ptr_type_node, ptr_type_node, NULL_TREE);
+ decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+ get_identifier (name), type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+
+ /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with
+ are the flags assigned by targetm.encode_section_info. */
+ SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
+
+ return decl;
+}
+
/* Extracts the personality function of DECL and returns the corresponding
libfunc. */
diff --git a/gcc/genhooks.cc b/gcc/genhooks.cc
index 8bcf9929207..0d4b13b7a71 100644
--- a/gcc/genhooks.cc
+++ b/gcc/genhooks.cc
@@ -35,6 +35,7 @@ static struct hook_desc hook_array[] = {
#include "c-family/c-target.def"
#include "common/common-target.def"
#include "d/d-target.def"
+#include "jit/jit-target.def"
#undef DEFHOOK
};
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
index 248ec45b729..cca0980b423 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/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 0687567bc88..7ef09d71288 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -20,6 +20,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"
@@ -29,8 +30,14 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "stringpool.h"
#include "attribs.h"
+#include "jit-recording.h"
+#include "print-tree.h"
#include
+#include
+#include
+
+using namespace gcc::jit;
/* Attribute handling. */
@@ -86,6 +93,10 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
ATTR_EXCL (NULL, false, false, false)
};
+hash_map target_builtins{};
+std::unordered_map target_function_types{};
+recording::context target_builtins_ctxt{NULL};
+
/* Table of machine-independent attributes supported in libgccjit. */
const struct attribute_spec jit_attribute_table[] =
{
@@ -146,6 +157,20 @@ const struct attribute_spec jit_format_attribute_table[] =
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
+char* jit_personality_func_name = NULL;
+static tree personality_decl;
+
+/* FIXME: This is a hack to preserve trees that we create from the
+ garbage collector. */
+
+static GTY (()) tree jit_gc_root;
+
+void
+jit_preserve_from_gc (tree t)
+{
+ jit_gc_root = tree_cons (NULL_TREE, t, jit_gc_root);
+}
+
/* Attribute handlers. */
/* Handle a "noreturn" attribute; arguments as in
@@ -507,12 +532,12 @@ struct GTY(()) lang_identifier
/* The resulting tree type. */
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
- chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
-lang_tree_node
-{
- union tree_node GTY((tag ("0"),
- desc ("tree_node_structure (&%h)"))) generic;
- struct lang_identifier GTY((tag ("1"))) identifier;
+ chain_next ("(union lang_tree_node *) jit_tree_chain_next (&%h.generic)"))) lang_tree_node
+ {
+ union tree_node GTY ((tag ("0"),
+ desc ("tree_node_structure (&%h)")))
+ generic;
+ struct lang_identifier GTY ((tag ("1"))) identifier;
};
/* We don't use language_function. */
@@ -578,6 +603,8 @@ jit_end_diagnostic (diagnostic_context *context,
static bool
jit_langhook_init (void)
{
+ jit_gc_root = NULL_TREE;
+ personality_decl = NULL_TREE;
gcc_assert (gcc::jit::active_playback_ctxt);
JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
@@ -592,15 +619,25 @@ jit_langhook_init (void)
global_dc->begin_diagnostic = jit_begin_diagnostic;
global_dc->end_diagnostic = jit_end_diagnostic;
- build_common_tree_nodes (false);
+ build_common_tree_nodes (flag_signed_char);
+
+ /* I don't know why this has to be done explicitly. */
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
+ target_builtins.empty ();
build_common_builtin_nodes ();
+ /* Initialize EH, if we've been told to do so. */
+ if (flag_exceptions)
+ using_eh_for_cleanups ();
+
/* The default precision for floating point numbers. This is used
for floating point constants with abstract type. This may
eventually be controllable by a command line option. */
mpfr_set_default_prec (256);
+ targetm.init_builtins ();
+
return true;
}
@@ -668,11 +705,216 @@ 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.
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
+ }
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ // For __builtin_sysv_va_copy.
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
+ }
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ {
+ if (type == FLOATN_NX_TYPE_NODE (i))
+ {
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
+ }
+ }
+ 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)
+ {
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
+ }
+ 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 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;
}
@@ -694,6 +936,25 @@ jit_langhook_getdecls (void)
return NULL;
}
+static tree
+jit_langhook_eh_personality (void)
+{
+ if (personality_decl == NULL_TREE)
+ {
+ if (jit_personality_func_name != NULL) {
+ personality_decl = build_personality_function_with_name (jit_personality_func_name);
+ jit_preserve_from_gc(personality_decl);
+ }
+ else {
+ return lhd_gcc_personality();
+ }
+ }
+ return personality_decl;
+}
+
+#undef LANG_HOOKS_EH_PERSONALITY
+#define LANG_HOOKS_EH_PERSONALITY jit_langhook_eh_personality
+
#undef LANG_HOOKS_NAME
#define LANG_HOOKS_NAME "libgccjit"
diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc
index fb86c77d0fe..622a061ea89 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;
@@ -609,6 +611,9 @@ builtins_manager::ensure_optimization_builtins_exist ()
We can't loop through all of the builtin_data array, we don't
support all types yet. */
(void)get_builtin_function_by_id (BUILT_IN_TRAP);
+ (void)get_builtin_function_by_id (BUILT_IN_POPCOUNT);
+ (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTL);
+ (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTLL);
}
/* Playback support. */
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 3ff7447fbf3..5c323411ea9 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see
#endif
#endif
-const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1;
+const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_BFLOAT16 + 1;
/* This comment is included by the docs.
@@ -93,6 +93,20 @@ const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1;
End of comment for inclusion in the docs. */
+static inline tree
+jit_tree_chain_next (tree t)
+{
+ /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different
+ kind of object, never a long chain of nodes. Prefer
+ TYPE_NEXT_VARIANT for types. */
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON))
+ return TYPE_NEXT_VARIANT (t);
+ /* Otherwise, if there is TREE_CHAIN, return it. */
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON))
+ return TREE_CHAIN (t);
+ return NULL;
+}
+
namespace gcc {
namespace jit {
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 96e9227af40..6fdda09eb1e 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#define INCLUDE_MUTEX
+#include "libgccjit.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
@@ -46,6 +47,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"
@@ -280,6 +282,8 @@ get_tree_node_for_type (enum gcc_jit_types type_)
case GCC_JIT_TYPE_FLOAT:
return float_type_node;
+ case GCC_JIT_TYPE_BFLOAT16:
+ return bfloat16_type_node;
case GCC_JIT_TYPE_DOUBLE:
return double_type_node;
case GCC_JIT_TYPE_LONG_DOUBLE:
@@ -326,7 +330,7 @@ playback::type *
playback::context::
new_array_type (playback::location *loc,
playback::type *element_type,
- int num_elements)
+ unsigned long num_elements)
{
gcc_assert (element_type);
@@ -407,7 +411,8 @@ playback::compound_type *
playback::context::
new_compound_type (location *loc,
const char *name,
- bool is_struct) /* else is union */
+ bool is_struct, /* else is union */
+ bool is_packed)
{
gcc_assert (name);
@@ -417,6 +422,9 @@ new_compound_type (location *loc,
TYPE_NAME (t) = get_identifier (name);
TYPE_SIZE (t) = 0;
+ if (is_packed)
+ TYPE_PACKED (t) = 1;
+
if (loc)
set_tree_location (t, loc);
@@ -424,7 +432,7 @@ new_compound_type (location *loc,
}
void
-playback::compound_type::set_fields (const auto_vec *fields)
+playback::compound_type::set_fields (const auto_vec *fields, bool is_packed)
{
/* Compare with c/c-decl.cc: finish_struct. */
tree t = as_tree ();
@@ -441,6 +449,10 @@ playback::compound_type::set_fields (const auto_vec *fields)
DECL_SIZE (x) = bitsize_int (width);
DECL_BIT_FIELD (x) = 1;
}
+
+ if (is_packed && (DECL_BIT_FIELD (x)
+ || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT))
+ DECL_PACKED (x) = 1;
fieldlist = chainon (x, fieldlist);
}
fieldlist = nreverse (fieldlist);
@@ -499,6 +511,40 @@ new_param (location *loc,
return new param (this, inner);
}
+const char* fn_attribute_to_string(gcc_jit_fn_attribute attr)
+{
+ switch (attr)
+ {
+ case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE:
+ return "always_inline";
+ case GCC_JIT_FN_ATTRIBUTE_INLINE:
+ return NULL;
+ case GCC_JIT_FN_ATTRIBUTE_NOINLINE:
+ return "noinline";
+ case GCC_JIT_FN_ATTRIBUTE_TARGET:
+ return "target";
+ case GCC_JIT_FN_ATTRIBUTE_USED:
+ return "used";
+ case GCC_JIT_FN_ATTRIBUTE_VISIBILITY:
+ return "visibility";
+ case GCC_JIT_FN_ATTRIBUTE_COLD:
+ return "cold";
+ case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE:
+ return "returns_twice";
+ }
+ return NULL;
+}
+
+const char* variable_attribute_to_string(gcc_jit_variable_attribute attr)
+{
+ switch (attr)
+ {
+ case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY:
+ return "visibility";
+ }
+ return NULL;
+}
+
/* Construct a playback::function instance. */
playback::function *
@@ -509,7 +555,10 @@ new_function (location *loc,
const char *name,
const auto_vec *params,
int is_variadic,
- enum built_in_function builtin_id)
+ enum built_in_function builtin_id,
+ const std::vector &attributes,
+ const std::vector> &string_attributes,
+ int is_target_builtin)
{
int i;
param *param;
@@ -532,6 +581,7 @@ new_function (location *loc,
/* FIXME: this uses input_location: */
tree fndecl = build_fn_decl (name, fn_type);
+ TREE_NOTHROW (fndecl) = 0;
if (loc)
set_tree_location (fndecl, loc);
@@ -543,6 +593,14 @@ new_function (location *loc,
DECL_RESULT (fndecl) = resdecl;
DECL_CONTEXT (resdecl) = fndecl;
+ 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);
@@ -594,6 +652,58 @@ new_function (location *loc,
DECL_ATTRIBUTES (fndecl));
}
+ for (auto attr: attributes)
+ {
+ if (attr == GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE)
+ {
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+ DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
+ }
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_NOINLINE)
+ DECL_UNINLINABLE (fndecl) = 1;
+ /* See handle_used_attribute in gcc/c-family/c-attribs.cc. */
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_USED)
+ {
+ TREE_USED (fndecl) = 1;
+ DECL_PRESERVE_P (fndecl) = 1;
+ }
+ /* See handle_returns_twice_attribute in gcc/c-family/c-attribs.cc. */
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE)
+ DECL_IS_RETURNS_TWICE (fndecl) = 1;
+ /* See handle_pure_attribute in gcc/c-family/c-attribs.cc. */
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_PURE)
+ DECL_PURE_P (fndecl) = 1;
+
+ const char* attribute = fn_attribute_to_string (attr);
+ if (attribute)
+ {
+ tree ident = get_identifier (attribute);
+ DECL_ATTRIBUTES (fndecl) =
+ tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl));
+ }
+ }
+
+ for (auto attr: string_attributes)
+ {
+ gcc_jit_fn_attribute& name = std::get<0>(attr);
+ std::string& value = std::get<1>(attr);
+ tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ()));
+ const char* attribute = fn_attribute_to_string (name);
+ tree ident = attribute ? get_identifier (attribute) : NULL;
+
+ /* See handle_target_attribute in gcc/c-family/c-attribs.cc. */
+ if (name == GCC_JIT_FN_ATTRIBUTE_TARGET)
+ /* We need to call valid_attribute_p so that the hook set-up some internal options. */
+ if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0))
+ continue;
+
+ if (ident)
+ DECL_ATTRIBUTES (fndecl) =
+ tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl));
+ }
+
function *func = new function (this, fndecl, kind);
m_functions.safe_push (func);
return func;
@@ -607,7 +717,9 @@ global_new_decl (location *loc,
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags)
+ enum global_var_flags flags,
+ bool readonly,
+ const std::vector> &attributes)
{
gcc_assert (type);
gcc_assert (name);
@@ -646,15 +758,33 @@ global_new_decl (location *loc,
break;
}
- if (TYPE_READONLY (type_tree))
+ if (TYPE_READONLY (type_tree) || readonly)
TREE_READONLY (inner) = 1;
if (loc)
set_tree_location (inner, loc);
+ set_variable_attribute (attributes, inner);
+
return inner;
}
+void
+playback::
+set_variable_attribute(const std::vector> &attributes, tree decl)
+{
+ for (auto attr: attributes)
+ {
+ gcc_jit_variable_attribute& name = std::get<0>(attr);
+ std::string& value = std::get<1>(attr);
+ tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ()));
+ tree ident = get_identifier (variable_attribute_to_string (name));
+
+ DECL_ATTRIBUTES (decl) =
+ tree_cons (ident, attribute_value, DECL_ATTRIBUTES (decl));
+ }
+}
+
/* In use by new_global and new_global_initialized. */
playback::lvalue *
@@ -674,10 +804,12 @@ new_global (location *loc,
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags)
+ enum global_var_flags flags,
+ bool readonly,
+ const std::vector> &attributes)
{
tree inner =
- global_new_decl (loc, kind, type, name, flags);
+ global_new_decl (loc, kind, type, name, flags, readonly, attributes);
return global_finalize_lvalue (inner);
}
@@ -822,9 +954,11 @@ new_global_initialized (location *loc,
size_t initializer_num_elem,
const void *initializer,
const char *name,
- enum global_var_flags flags)
+ enum global_var_flags flags,
+ bool readonly,
+ const std::vector> &attributes)
{
- tree inner = global_new_decl (loc, kind, type, name, flags);
+ tree inner = global_new_decl (loc, kind, type, name, flags, readonly, attributes);
vec *constructor_elements = NULL;
@@ -1007,10 +1141,30 @@ playback::context::new_rvalue_from_vector (location *,
vec_alloc (v, elements.length ());
for (unsigned i = 0; i < elements.length (); ++i)
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
- tree t_ctor = build_constructor (type->as_tree (), v);
+ tree t_ctor;
+ t_ctor = build_constructor (type->as_tree (), v);
return new rvalue (this, t_ctor);
}
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ vector perm. */
+
+playback::rvalue *
+playback::context::new_rvalue_vector_perm (location *loc,
+ rvalue* elements1,
+ rvalue* elements2,
+ rvalue* mask)
+{
+ tree t_elements1 = elements1->as_tree ();
+ tree t_elements2 = elements2->as_tree ();
+ tree t_mask = mask->as_tree ();
+
+ tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1), t_elements1, t_elements2, t_mask);
+ if (loc)
+ set_tree_location (t_vector_perm, loc);
+ return new rvalue (this, t_vector_perm);
+}
+
/* Coerce a tree expression into a boolean tree expression. */
tree
@@ -1527,6 +1681,163 @@ new_array_access (location *loc,
}
}
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ vector conversion. */
+
+playback::rvalue *
+playback::context::
+convert_vector (location *loc,
+ rvalue *vector,
+ type *type)
+{
+ gcc_assert (vector);
+ gcc_assert (type);
+
+ /* For comparison, see:
+ c/c-common.cc: c_build_vec_convert
+ */
+
+ tree t_vector = vector->as_tree ();
+
+ /* It seems IFN_VEC_CONVERT only work on registers, not on memory. */
+ if (TREE_CODE (t_vector) == VAR_DECL)
+ DECL_REGISTER (t_vector) = 1;
+ tree t_result = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT, type->as_tree (), 1, t_vector);
+
+ if (loc)
+ set_tree_location (t_result, loc);
+
+ return new rvalue (this, t_result);
+}
+
+/* The following functions come from c-common.h. */
+/* Like c_mark_addressable but don't check register qualifier. */
+void
+common_mark_addressable_vec (tree t)
+{
+ while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR)
+ {
+ t = TREE_OPERAND (t, 0);
+ }
+ if (!VAR_P (t)
+ && TREE_CODE (t) != PARM_DECL
+ && TREE_CODE (t) != COMPOUND_LITERAL_EXPR
+ && TREE_CODE (t) != TARGET_EXPR)
+ return;
+ if (!VAR_P (t) || !DECL_HARD_REGISTER (t))
+ TREE_ADDRESSABLE (t) = 1;
+ if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR)
+ TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1;
+ else if (TREE_CODE (t) == TARGET_EXPR)
+ TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1;
+}
+
+/* Return true if TYPE is a vector type that should be subject to the GNU
+ vector extensions (as opposed to a vector type that is used only for
+ the purposes of defining target-specific built-in functions). */
+
+inline bool
+gnu_vector_type_p (const_tree type)
+{
+ return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
+}
+
+/* Return nonzero if REF is an lvalue valid for this language.
+ Lvalues can be assigned, unless their type has TYPE_READONLY.
+ Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
+
+bool
+lvalue_p (const_tree ref)
+{
+ const enum tree_code code = TREE_CODE (ref);
+
+ switch (code)
+ {
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case COMPONENT_REF:
+ return lvalue_p (TREE_OPERAND (ref, 0));
+
+ case C_MAYBE_CONST_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 1));
+
+ case COMPOUND_LITERAL_EXPR:
+ case STRING_CST:
+ return true;
+
+ case MEM_REF:
+ case TARGET_MEM_REF:
+ /* MEM_REFs can appear from -fgimple parsing or folding, so allow them
+ here as well. */
+ case INDIRECT_REF:
+ case ARRAY_REF:
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case ERROR_MARK:
+ return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
+
+ case BIND_EXPR:
+ return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
+
+ default:
+ return false;
+ }
+}
+
+bool
+convert_vector_to_array_for_subscript (tree *vecp)
+{
+ bool ret = false;
+ if (gnu_vector_type_p (TREE_TYPE (*vecp)))
+ {
+ tree type = TREE_TYPE (*vecp);
+
+ ret = !lvalue_p (*vecp);
+
+ /* We are building an ARRAY_REF so mark the vector as addressable
+ to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P
+ for function parameters. */
+ // NOTE: that was the missing piece for making vector access work with optimizations enabled.
+ common_mark_addressable_vec (*vecp);
+
+ *vecp = build1 (VIEW_CONVERT_EXPR,
+ build_array_type_nelts (TREE_TYPE (type),
+ TYPE_VECTOR_SUBPARTS (type)),
+ *vecp);
+ }
+ return ret;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+ vector access. */
+
+playback::lvalue *
+playback::context::
+new_vector_access (location *loc,
+ rvalue *vector,
+ rvalue *index)
+{
+ gcc_assert (vector);
+ gcc_assert (index);
+
+ /* For comparison, see:
+ c/c-typeck.cc: build_array_ref
+ */
+
+ tree t_vector = vector->as_tree ();
+ bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector);
+ tree type = TREE_TYPE (TREE_TYPE (t_vector));
+ tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (), NULL_TREE, NULL_TREE);
+ if (non_lvalue)
+ t_result = non_lvalue (t_result);
+
+ if (loc)
+ set_tree_location (t_result, loc);
+ return new lvalue (this, t_result);
+}
+
/* Construct a tree for a field access. */
tree
@@ -1812,7 +2123,8 @@ playback::lvalue *
playback::function::
new_local (location *loc,
type *type,
- const char *name)
+ const char *name,
+ const std::vector> &attributes)
{
gcc_assert (type);
gcc_assert (name);
@@ -1825,6 +2137,8 @@ new_local (location *loc,
DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
BIND_EXPR_VARS (m_inner_bind_expr) = inner;
+ set_variable_attribute (attributes, inner);
+
if (loc)
set_tree_location (inner, loc);
return new lvalue (m_ctxt, inner);
@@ -1857,6 +2171,15 @@ playback::function::get_address (location *loc)
return new rvalue (m_ctxt, t_fnptr);
}
+/* Construct a new local within this playback::function. */
+
+void
+playback::function::
+set_personality_function (function *personality_function)
+{
+ DECL_FUNCTION_PERSONALITY (m_inner_fndecl) = personality_function->as_fndecl ();
+}
+
/* Build a statement list for the function as a whole out of the
lists of statements for the individual blocks, building labels
for each block. */
@@ -1875,6 +2198,11 @@ build_stmt_list ()
int j;
tree stmt;
+ // Do not add try/catch block to the function.
+ // TODO: explain why.
+ if (b->m_is_try_or_catch)
+ continue;
+
b->m_label_expr = build1 (LABEL_EXPR,
void_type_node,
b->as_label_decl ());
@@ -1973,6 +2301,70 @@ add_eval (location *loc,
add_stmt (rvalue->as_tree ());
}
+
+void
+playback::block::
+add_try_catch (location *loc,
+ block *try_block,
+ block *catch_block,
+ bool is_finally)
+{
+ gcc_assert (try_block);
+ gcc_assert (catch_block);
+
+ try_block->m_is_try_or_catch = true;
+ catch_block->m_is_try_or_catch = true;
+
+ if (loc)
+ {
+ set_tree_location (try_block->as_label_decl (), loc);
+ set_tree_location (catch_block->as_label_decl (), loc);
+ }
+
+ tree try_body = alloc_stmt_list ();
+ unsigned int i;
+ tree stmt;
+ FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) {
+ append_to_statement_list (stmt, &try_body);
+ }
+
+ tree catch_body = alloc_stmt_list ();
+ unsigned int j;
+ tree catch_stmt;
+ FOR_EACH_VEC_ELT (catch_block->m_stmts, j, catch_stmt) {
+ append_to_statement_list (catch_stmt, &catch_body);
+ }
+
+ if (is_finally)
+ {
+ tree success_body = alloc_stmt_list ();
+
+ // TODO: find a better way to keep the EH_ELSE_EXPR than creating an empty inline asm.
+ tree t_string = build_string ("");
+ tree asm_stmt
+ = build5 (ASM_EXPR, void_type_node, t_string, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+
+ // asm statements without outputs, including simple ones, are treated
+ // as volatile.
+ ASM_VOLATILE_P (asm_stmt) = 1;
+ ASM_INPUT_P (asm_stmt) = 0;
+ append_to_statement_list (asm_stmt, &success_body);
+
+ // TODO: Don't automatically add the `EH_ELSE_EXPR`. Make an API to create such a node and let the user of libgccjit
+ // add it manually.
+ catch_body = build2 (EH_ELSE_EXPR, void_type_node, success_body, catch_body);
+ add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node,
+ try_body, catch_body));
+ }
+ else
+ {
+ catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
+ tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node,
+ try_body, catch_body);
+ add_stmt (try_catch);
+ }
+}
+
/* Add an assignment to the function's statement list. */
void
@@ -3226,6 +3618,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 43e92d67d74..d153f4945d8 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see
#ifndef JIT_PLAYBACK_H
#define JIT_PLAYBACK_H
+#include
#include // for std::pair
+#include
#include "timevar.h"
#include "varasm.h"
@@ -41,11 +43,15 @@ namespace jit {
namespace playback {
+void
+set_variable_attribute(const std::vector> &attributes, tree decl);
+
/* 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
{
@@ -69,7 +75,7 @@ public:
type *
new_array_type (location *loc,
type *element_type,
- int num_elements);
+ unsigned long num_elements);
field *
new_field (location *loc,
@@ -85,7 +91,8 @@ public:
compound_type *
new_compound_type (location *loc,
const char *name,
- bool is_struct); /* else is union */
+ bool is_struct, /* else is union */
+ bool is_packed);
type *
new_function_type (type *return_type,
@@ -104,14 +111,19 @@ public:
const char *name,
const auto_vec *params,
int is_variadic,
- enum built_in_function builtin_id);
+ enum built_in_function builtin_id,
+ const std::vector &attributes,
+ const std::vector> &string_attributes,
+ int is_target_builtin);
lvalue *
new_global (location *loc,
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags);
+ enum global_var_flags flags,
+ bool readonly,
+ const std::vector> &attributes);
lvalue *
new_global_initialized (location *loc,
@@ -121,7 +133,9 @@ public:
size_t initializer_num_elem,
const void *initializer,
const char *name,
- enum global_var_flags flags);
+ enum global_var_flags flags,
+ bool readonly,
+ const std::vector> &attributes);
rvalue *
new_ctor (location *log,
@@ -147,6 +161,12 @@ public:
type *type,
const auto_vec &elements);
+ rvalue *
+ new_rvalue_vector_perm (location *loc,
+ rvalue* elements1,
+ rvalue* elements2,
+ rvalue* mask);
+
rvalue *
new_unary_op (location *loc,
enum gcc_jit_unary_op op,
@@ -191,6 +211,16 @@ public:
rvalue *ptr,
rvalue *index);
+ rvalue *
+ convert_vector (location *loc,
+ rvalue *vector,
+ type *type);
+
+ lvalue *
+ new_vector_access (location *loc,
+ rvalue *vector,
+ rvalue *index);
+
void
set_str_option (enum gcc_jit_str_option opt,
const char *value);
@@ -306,7 +336,9 @@ private:
enum gcc_jit_global_kind kind,
type *type,
const char *name,
- enum global_var_flags flags);
+ enum global_var_flags flags,
+ bool readonly,
+ const std::vector> &attributes);
lvalue *
global_finalize_lvalue (tree inner);
@@ -405,6 +437,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.
@@ -460,7 +504,7 @@ public:
: type (inner)
{}
- void set_fields (const auto_vec *fields);
+ void set_fields (const auto_vec *fields, bool is_packed);
};
class field : public wrapper
@@ -495,7 +539,8 @@ public:
lvalue *
new_local (location *loc,
type *type,
- const char *name);
+ const char *name,
+ const std::vector> &attributes);
block*
new_block (const char *name);
@@ -503,6 +548,9 @@ public:
rvalue *
get_address (location *loc);
+ void
+ set_personality_function (function *personality_function);
+
void
build_stmt_list ();
@@ -573,6 +621,12 @@ public:
add_eval (location *loc,
rvalue *rvalue);
+ void
+ add_try_catch (location *loc,
+ block *try_block,
+ block *catch_block,
+ bool is_finally);
+
void
add_assignment (location *loc,
lvalue *lvalue,
@@ -636,6 +690,7 @@ private:
public: // for now
tree m_label_expr;
+ bool m_is_try_or_catch = false;
friend class function;
};
@@ -813,4 +868,6 @@ extern playback::context *active_playback_ctxt;
} // namespace gcc
+extern hash_map target_builtins;
+
#endif /* JIT_PLAYBACK_H */
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 2ce272267b8..f962c9748c4 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -840,9 +840,9 @@ recording::context::get_int_type (int num_bytes, int is_signed)
recording::type *
recording::context::new_array_type (recording::location *loc,
recording::type *element_type,
- int num_elements)
+ unsigned long num_elements)
{
- if (struct_ *s = element_type->dyn_cast_struct ())
+ /*if (struct_ *s = element_type->dyn_cast_struct ())
if (!s->get_fields ())
{
add_error (NULL,
@@ -850,7 +850,7 @@ recording::context::new_array_type (recording::location *loc,
" until the fields have been set",
s->get_name ()->c_str ());
return NULL;
- }
+ }*/
recording::type *result =
new recording::array_type (this, loc, element_type, num_elements);
record (result);
@@ -933,14 +933,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,
+ int 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;
}
@@ -962,7 +964,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 ();
@@ -1005,7 +1008,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);
@@ -1044,6 +1047,52 @@ 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& 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, // FIXME
+ 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.
@@ -1108,6 +1157,18 @@ recording::context::new_rvalue_from_vector (location *loc,
return result;
}
+recording::rvalue *
+recording::context::new_rvalue_vector_perm (location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask)
+{
+ recording::rvalue *result
+ = new memento_of_new_rvalue_vector_perm (this, loc, elements1, elements2, mask);
+ record (result);
+ return result;
+}
+
recording::rvalue *
recording::context::new_ctor (recording::location *loc,
recording::type *type,
@@ -1309,6 +1370,39 @@ recording::context::new_array_access (recording::location *loc,
return result;
}
+/* Create a recording::convert_vector instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_convert_vector. */
+
+recording::rvalue *
+recording::context::new_convert_vector (recording::location *loc,
+ recording::rvalue *vector,
+ recording::type *type)
+{
+ // TODO: instead have an "internal function" memento?
+ recording::rvalue *result = new convert_vector (this, loc, vector, type);
+ record (result);
+ return result;
+}
+
+/* Create a recording::vector_access instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_vector_access. */
+
+recording::lvalue *
+recording::context::new_vector_access (recording::location *loc,
+ recording::rvalue *vector,
+ recording::rvalue *index)
+{
+ recording::lvalue *result = new vector_access (this, loc, vector, index);
+ record (result);
+ return result;
+}
+
/* Create a recording::case_ instance and add it to this context's list
of mementos.
@@ -1525,6 +1619,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. */
@@ -2294,6 +2407,12 @@ recording::type::get_aligned (size_t alignment_in_bytes)
return result;
}
+void
+recording::type::set_packed ()
+{
+ m_packed = true;
+}
+
/* Given a type, get a vector version of the type.
Implements the post-error-checking part of
@@ -2372,6 +2491,10 @@ recording::memento_of_get_type::get_size ()
case GCC_JIT_TYPE_FLOAT:
size = FLOAT_TYPE_SIZE;
break;
+ #ifdef HAVE_BFmode
+ case GCC_JIT_TYPE_BFLOAT16:
+ return GET_MODE_UNIT_SIZE (BFmode);
+ #endif
case GCC_JIT_TYPE_DOUBLE:
size = DOUBLE_TYPE_SIZE;
break;
@@ -2431,6 +2554,7 @@ recording::memento_of_get_type::dereference ()
case GCC_JIT_TYPE_INT64_T:
case GCC_JIT_TYPE_INT128_T:
case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_BFLOAT16:
case GCC_JIT_TYPE_DOUBLE:
case GCC_JIT_TYPE_LONG_DOUBLE:
case GCC_JIT_TYPE_COMPLEX_FLOAT:
@@ -2495,6 +2619,7 @@ recording::memento_of_get_type::is_int () const
return true;
case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_BFLOAT16:
case GCC_JIT_TYPE_DOUBLE:
case GCC_JIT_TYPE_LONG_DOUBLE:
return false;
@@ -2553,6 +2678,7 @@ recording::memento_of_get_type::is_signed () const
case GCC_JIT_TYPE_UINT128_T:
case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_BFLOAT16:
case GCC_JIT_TYPE_DOUBLE:
case GCC_JIT_TYPE_LONG_DOUBLE:
@@ -2612,6 +2738,7 @@ recording::memento_of_get_type::is_float () const
return false;
case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_BFLOAT16:
case GCC_JIT_TYPE_DOUBLE:
case GCC_JIT_TYPE_LONG_DOUBLE:
return true;
@@ -2675,6 +2802,7 @@ recording::memento_of_get_type::is_bool () const
return false;
case GCC_JIT_TYPE_FLOAT:
+ case GCC_JIT_TYPE_BFLOAT16:
case GCC_JIT_TYPE_DOUBLE:
case GCC_JIT_TYPE_LONG_DOUBLE:
return false;
@@ -2754,6 +2882,7 @@ static const char * const get_type_strings[] = {
"__int32_t", /* GCC_JIT_TYPE_INT32_T */
"__int64_t", /* GCC_JIT_TYPE_INT64_T */
"__int128_t", /* GCC_JIT_TYPE_INT128_T */
+ "bfloat16", /* GCC_JIT_TYPE_BFLOAT16 */
};
@@ -2800,6 +2929,7 @@ static const char * const get_type_enum_strings[] = {
"GCC_JIT_TYPE_INT32_T",
"GCC_JIT_TYPE_INT64_T",
"GCC_JIT_TYPE_INT128_T",
+ "GCC_JIT_TYPE_BFLOAT16",
};
void
@@ -3066,7 +3196,7 @@ recording::string *
recording::array_type::make_debug_string ()
{
return string::from_printf (m_ctxt,
- "%s[%d]",
+ "%s[%ld]",
m_element_type->get_debug_string (),
m_num_elements);
}
@@ -3082,7 +3212,7 @@ recording::array_type::write_reproducer (reproducer &r)
" gcc_jit_context_new_array_type (%s,\n"
" %s, /* gcc_jit_location *loc */\n"
" %s, /* gcc_jit_type *element_type */\n"
- " %i); /* int num_elements */\n",
+ " %li); /* int num_elements */\n",
id,
r.get_identifier (get_context ()),
r.get_identifier (m_loc),
@@ -3098,11 +3228,13 @@ recording::function_type::function_type (context *ctxt,
type *return_type,
int num_params,
type **param_types,
- int is_variadic)
+ int is_variadic,
+ int 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]);
@@ -3484,7 +3616,8 @@ recording::struct_::replay_into (replayer *r)
set_playback_obj (
r->new_compound_type (playback_location (r, get_loc ()),
get_name ()->c_str (),
- true /* is_struct */));
+ true, /* is_struct */
+ m_packed));
}
const char *
@@ -3538,7 +3671,8 @@ recording::union_::replay_into (replayer *r)
set_playback_obj (
r->new_compound_type (playback_location (r, get_loc ()),
get_name ()->c_str (),
- false /* is_struct */));
+ false, /* is_struct */
+ m_packed));
}
/* Implementation of recording::memento::make_debug_string for
@@ -3609,7 +3743,7 @@ recording::fields::replay_into (replayer *)
playback_fields.create (m_fields.length ());
for (unsigned i = 0; i < m_fields.length (); i++)
playback_fields.safe_push (m_fields[i]->playback_field ());
- m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields);
+ m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields, m_struct_or_union->m_packed);
}
/* Override the default implementation of
@@ -3979,6 +4113,11 @@ void recording::lvalue::set_alignment (unsigned bytes)
m_alignment = bytes;
}
+void recording::lvalue::add_attribute (gcc_jit_variable_attribute attribute, const char* value)
+{
+ m_attributes.push_back (std::make_pair (attribute, std::string (value)));
+}
+
/* The implementation of class gcc::jit::recording::param. */
/* Implementation of pure virtual hook recording::memento::replay_into
@@ -4044,7 +4183,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,
+ int is_target_builtin)
: memento (ctxt),
m_loc (loc),
m_kind (kind),
@@ -4055,7 +4195,10 @@ recording::function::function (context *ctxt,
m_builtin_id (builtin_id),
m_locals (),
m_blocks (),
- m_fn_ptr_type (NULL)
+ m_fn_ptr_type (NULL),
+ m_attributes(),
+ m_string_attributes(),
+ m_is_target_builtin (is_target_builtin)
{
for (int i = 0; i< num_params; i++)
{
@@ -4114,7 +4257,40 @@ recording::function::replay_into (replayer *r)
m_name->c_str (),
¶ms,
m_is_variadic,
- m_builtin_id));
+ m_builtin_id,
+ m_attributes,
+ m_string_attributes,
+ m_is_target_builtin));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ setting a personality function. */
+
+recording::string *
+recording::memento_of_set_personality_function::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s",
+ m_personality_function->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for setting the personality function. */
+
+void
+recording::memento_of_set_personality_function::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_function_set_personality_function (%s,\n"
+ " %s);\n",
+ r.get_identifier (m_function),
+ r.get_identifier (m_personality_function));
+}
+
+void
+recording::function::set_personality_function (function *function)
+{
+ recording::memento_of_set_personality_function *result =
+ new memento_of_set_personality_function (m_ctxt, this, function);
+ m_ctxt->record (result);
}
/* Create a recording::local instance and add it to
@@ -4259,6 +4435,13 @@ recording::function::validate ()
/* Iteratively walk the graph of blocks, marking their "m_is_reachable"
flag, starting at the initial block. */
auto_vec worklist (m_blocks.length ());
+ int j;
+ block *func_block;
+ /* Push the blocks used in try/catch because they're not successors of
+ other blocks. */
+ FOR_EACH_VEC_ELT (m_blocks, j, func_block)
+ if (func_block->m_is_reachable)
+ worklist.safe_push (func_block);
worklist.safe_push (m_blocks[0]);
while (worklist.length () > 0)
{
@@ -4347,7 +4530,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);
@@ -4357,6 +4541,18 @@ recording::function::get_address (recording::location *loc)
return result;
}
+void
+recording::function::add_attribute (gcc_jit_fn_attribute attribute)
+{
+ m_attributes.push_back (attribute);
+}
+
+void
+recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, const char* value)
+{
+ m_string_attributes.push_back (std::make_pair (attribute, std::string (value)));
+}
+
/* Implementation of recording::memento::make_debug_string for
functions. */
@@ -4441,6 +4637,31 @@ recording::block::add_eval (recording::location *loc,
return result;
}
+/* The implementation of class gcc::jit::recording::block. */
+
+/* Create a recording::try_catch instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+ Implements the heart of gcc_jit_block_add_try_catch. */
+
+recording::statement *
+recording::block::add_try_catch (location *loc,
+ block *try_block,
+ block *catch_block,
+ bool is_finally)
+{
+ statement *result = new try_catch (this, loc, try_block, catch_block, is_finally);
+ // TODO: explain why we set the blocks reachable state.
+ try_block->m_is_reachable = true;
+ catch_block->m_is_reachable = true;
+ /* The finally block can fallthrough, so we don't require the user to terminate it. */
+ if (is_finally)
+ catch_block->m_has_been_terminated = true;
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
/* Create a recording::assignment instance and add it to
the block's context's list of mementos, and to the block's
list of statements.
@@ -4832,12 +5053,16 @@ recording::global::replay_into (replayer *r)
/ m_type->dereference ()->get_size (),
m_initializer,
playback_string (m_name),
- m_flags)
+ m_flags,
+ m_readonly,
+ m_attributes)
: r->new_global (playback_location (r, m_loc),
m_kind,
m_type->playback_type (),
playback_string (m_name),
- m_flags);
+ m_flags,
+ m_readonly,
+ m_attributes);
if (m_tls_model != GCC_JIT_TLS_MODEL_NONE)
global->set_tls_model (recording::tls_models[m_tls_model]);
@@ -5390,6 +5615,91 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
elements_id);
}
+/* The implementation of class
+ gcc::jit::recording::memento_of_new_rvalue_vector_perm. */
+
+/* The constructor for
+ gcc::jit::recording::memento_of_new_rvalue_vector_perm. */
+
+recording::memento_of_new_rvalue_vector_perm::
+memento_of_new_rvalue_vector_perm (context *ctxt,
+ location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask)
+: rvalue (ctxt, loc, elements1->get_type ()),
+ m_elements1 (elements1),
+ m_elements2 (elements2),
+ m_mask (mask)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_new_rvalue_vector_perm. */
+
+void
+recording::memento_of_new_rvalue_vector_perm::replay_into (replayer *r)
+{
+ playback::rvalue *playback_elements1 = m_elements1->playback_rvalue ();
+ playback::rvalue *playback_elements2 = m_elements2->playback_rvalue ();
+ playback::rvalue *playback_mask = m_mask->playback_rvalue ();
+
+ set_playback_obj (r->new_rvalue_vector_perm (playback_location (r, m_loc),
+ playback_elements1,
+ playback_elements2,
+ playback_mask));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::memento_of_new_rvalue_from_vector. */
+
+ void
+recording::memento_of_new_rvalue_vector_perm::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_elements1);
+ v->visit (m_elements2);
+ v->visit (m_mask);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ vectors. */
+
+ recording::string *
+recording::memento_of_new_rvalue_vector_perm::make_debug_string ()
+{
+ /* Now build a string. */
+ string *result = string::from_printf (m_ctxt,
+ "shufflevector(%s, %s, %s)",
+ m_elements1->get_debug_string (),
+ m_elements2->get_debug_string (),
+ m_mask->get_debug_string ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ vectors. */
+
+ void
+recording::memento_of_new_rvalue_vector_perm::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "vector");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_vector_perm (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue **elements1*/\n"
+ " %s, /* gcc_jit_rvalue **elements2*/\n"
+ " %s); /* gcc_jit_rvalue **mask*/\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_elements1),
+ r.get_identifier_as_rvalue (m_elements2),
+ r.get_identifier_as_rvalue (m_mask));
+}
+
+
void
recording::ctor::visit_children (rvalue_visitor *v)
{
@@ -6260,6 +6570,114 @@ recording::array_access::write_reproducer (reproducer &r)
r.get_identifier_as_rvalue (m_index));
}
+/* The implementation of class gcc::jit::recording::convert_vector. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::convert_vector. */
+
+void
+recording::convert_vector::replay_into (replayer *r)
+{
+ set_playback_obj (
+ r->convert_vector (playback_location (r, m_loc),
+ m_vector->playback_rvalue (),
+ m_type->playback_type ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::convert_vector. */
+
+void
+recording::convert_vector::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_vector);
+}
+
+/* The implementation of class gcc::jit::recording::vector_access. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::vector_access. */
+
+void
+recording::vector_access::replay_into (replayer *r)
+{
+ set_playback_obj (
+ r->new_vector_access (playback_location (r, m_loc),
+ m_vector->playback_rvalue (),
+ m_index->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::vector_access. */
+
+void
+recording::vector_access::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_vector);
+ v->visit (m_index);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ array accesses. */
+
+recording::string *
+recording::convert_vector::make_debug_string ()
+{
+ enum precedence prec = get_precedence ();
+ return string::from_printf (m_ctxt,
+ "(%s)%s",
+ m_type->get_debug_string (),
+ m_vector->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ convert_vector. */
+
+void
+recording::convert_vector::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "lvalue");
+ r.write (" gcc_jit_lvalue *%s = \n"
+ " gcc_jit_context_convert_vector (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /*gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *vector */\n"
+ " %s); /* gcc_jit_type *type */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_vector),
+ r.get_identifier_as_type (m_type));
+}
+
+recording::string *
+recording::vector_access::make_debug_string ()
+{
+ enum precedence prec = get_precedence ();
+ return string::from_printf (m_ctxt,
+ "%s[%s]",
+ m_vector->get_debug_string_parens (prec),
+ m_index->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ vector_access. */
+
+void
+recording::vector_access::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "lvalue");
+ r.write (" gcc_jit_lvalue *%s = \n"
+ " gcc_jit_context_new_vector_access (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /*gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *vector */\n"
+ " %s); /* gcc_jit_rvalue *index */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_vector),
+ r.get_identifier_as_rvalue (m_index));
+}
+
/* The implementation of class gcc::jit::recording::access_field_of_lvalue. */
/* Implementation of pure virtual hook recording::memento::replay_into
@@ -6575,7 +6993,8 @@ recording::local::replay_into (replayer *r)
playback::lvalue *obj = m_func->playback_function ()
->new_local (playback_location (r, m_loc),
m_type->playback_type (),
- playback_string (m_name));
+ playback_string (m_name),
+ m_attributes);
if (m_reg_name != NULL)
obj->set_register_name (m_reg_name->c_str ());
@@ -6649,6 +7068,17 @@ recording::statement::write_to_dump (dump &d)
m_loc = d.make_location ();
}
+/* The implementation of class gcc::jit::recording::memento_of_set_personality_function. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_set_personality_function. */
+
+void
+recording::memento_of_set_personality_function::replay_into (replayer *r)
+{
+ m_function->playback_function ()->set_personality_function (m_personality_function->playback_function ());
+}
+
/* The implementation of class gcc::jit::recording::eval. */
/* Implementation of pure virtual hook recording::memento::replay_into
@@ -6687,6 +7117,59 @@ recording::eval::write_reproducer (reproducer &r)
r.get_identifier_as_rvalue (m_rvalue));
}
+/* The implementation of class gcc::jit::recording::try_catch. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::try_catch. */
+
+void
+recording::try_catch::replay_into (replayer *r)
+{
+ playback_block (get_block ())
+ ->add_try_catch (playback_location (r),
+ m_try_block->playback_block (),
+ m_catch_block->playback_block (),
+ m_is_finally);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ an eval statement. */
+
+recording::string *
+recording::try_catch::make_debug_string ()
+{
+ if (m_is_finally)
+ return string::from_printf (m_ctxt,
+ "try { %s } finally { %s };",
+ m_try_block->get_debug_string (),
+ m_catch_block->get_debug_string ());
+ else
+ return string::from_printf (m_ctxt,
+ "try { %s } catch { %s };",
+ m_try_block->get_debug_string (),
+ m_catch_block->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ eval statements. */
+
+void
+recording::try_catch::write_reproducer (reproducer &r)
+{
+ const char *func_name = "gcc_jit_block_add_try_catch";
+ if (m_is_finally)
+ func_name = "gcc_jit_block_add_try_finally";
+ r.write (" %s (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_block *try_block */\n"
+ " %s); /* gcc_jit_block *catch_block */\n",
+ func_name,
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ r.get_identifier (m_try_block),
+ r.get_identifier (m_catch_block));
+}
+
/* The implementation of class gcc::jit::recording::assignment. */
/* Implementation of pure virtual hook recording::memento::replay_into
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index e1236dec575..929bbe37c3f 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -23,13 +23,21 @@ along with GCC; see the file COPYING3. If not see
#include "jit-common.h"
#include "jit-logging.h"
+#include "libgccjit.h"
+
+#include
+#include
+
+#include
+#include
class timer;
+extern std::unordered_map target_function_types;
+
namespace gcc {
namespace jit {
-
extern const char * const unary_op_reproducer_strings[];
extern const char * const binary_op_reproducer_strings[];
@@ -91,7 +99,7 @@ public:
type *
new_array_type (location *loc,
type *element_type,
- int num_elements);
+ unsigned long num_elements);
field *
new_field (location *loc,
@@ -116,7 +124,8 @@ public:
new_function_type (type *return_type,
int num_params,
type **param_types,
- int is_variadic);
+ int is_variadic,
+ int is_target_builtin);
type *
new_function_ptr_type (location *loc,
@@ -143,6 +152,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,
@@ -173,6 +185,12 @@ public:
vector_type *type,
rvalue **elements);
+ rvalue *
+ new_rvalue_vector_perm (location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask);
+
rvalue *
new_unary_op (location *loc,
enum gcc_jit_unary_op op,
@@ -215,6 +233,16 @@ public:
rvalue *ptr,
rvalue *index);
+ rvalue *
+ new_convert_vector (location *loc,
+ rvalue *vector,
+ type *type);
+
+ lvalue *
+ new_vector_access (location *loc,
+ rvalue *vector,
+ rvalue *index);
+
case_ *
new_case (rvalue *min_value,
rvalue *max_value,
@@ -283,6 +311,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);
@@ -527,6 +558,8 @@ public:
type *get_aligned (size_t alignment_in_bytes);
type *get_vector (size_t num_units);
+ void set_packed ();
+
/* Get the type obtained when dereferencing this type.
This will return NULL if it's not valid to dereference this type.
@@ -539,6 +572,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; }
@@ -593,9 +628,13 @@ public:
protected:
type (context *ctxt)
: memento (ctxt),
+ m_packed (false),
m_pointer_to_this_type (NULL)
{}
+public:
+ bool m_packed;
+
private:
type *m_pointer_to_this_type;
};
@@ -613,6 +652,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)
@@ -664,6 +708,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;
@@ -699,6 +750,7 @@ public:
size_t get_size () final override { return m_other_type->get_size (); };
+ // FIXME: this is wrong. A vector is not an int.
bool is_int () const final override { return m_other_type->is_int (); }
bool is_float () const final override { return m_other_type->is_float (); }
bool is_bool () const final override { return m_other_type->is_bool (); }
@@ -718,10 +770,11 @@ public:
memento_of_get_const (type *other_type)
: decorated_type (other_type) {}
- bool accepts_writes_from (type */*rtype*/) final override
+ type* copy(context* ctxt) final override
{
- /* Can't write to a "const". */
- return false;
+ 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. */
@@ -757,6 +810,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; }
@@ -777,11 +837,20 @@ public:
: decorated_type (other_type),
m_alignment_in_bytes (alignment_in_bytes) {}
+ 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; }
void replay_into (replayer *) final override;
+ vector_type *dyn_cast_vector_type () final override { return m_other_type->dyn_cast_vector_type (); }
+
private:
string * make_debug_string () final override;
void write_reproducer (reproducer &r) final override;
@@ -798,6 +867,13 @@ public:
: decorated_type (other_type),
m_num_units (num_units) {}
+ 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; }
@@ -831,7 +907,7 @@ class array_type : public type
array_type (context *ctxt,
location *loc,
type *element_type,
- int num_elements)
+ unsigned long num_elements)
: type (ctxt),
m_loc (loc),
m_element_type (element_type),
@@ -840,12 +916,19 @@ class array_type : public type
type *dereference () final override;
+ 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; }
type *is_pointer () final override { return NULL; }
type *is_array () final override { return m_element_type; }
- int num_elements () { return m_num_elements; }
+ unsigned long num_elements () { return m_num_elements; }
bool is_signed () const final override { return false; }
void replay_into (replayer *) final override;
@@ -857,7 +940,7 @@ class array_type : public type
private:
location *m_loc;
type *m_element_type;
- int m_num_elements;
+ unsigned long m_num_elements;
};
class function_type : public type
@@ -867,7 +950,8 @@ public:
type *return_type,
int num_params,
type **param_types,
- int is_variadic);
+ int is_variadic,
+ int is_target_builtin);
type *dereference () final override;
function_type *dyn_cast_function_type () final override { return this; }
@@ -875,6 +959,18 @@ public:
bool is_same_type_as (type *other) final override;
+ type* copy(context* ctxt) final override
+ {
+ auto_vec 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; }
@@ -887,6 +983,7 @@ public:
type * get_return_type () const { return m_return_type; }
const vec &get_param_types () const { return m_param_types; }
int is_variadic () const { return m_is_variadic; }
+ int is_target_builtin () const { return m_is_target_builtin; }
string * make_debug_string_with_ptr ();
@@ -903,6 +1000,7 @@ private:
type *m_return_type;
auto_vec m_param_types;
int m_is_variadic;
+ int m_is_target_builtin;
};
class field : public memento
@@ -1004,9 +1102,11 @@ public:
return static_cast (m_playback_obj);
}
-private:
+protected:
location *m_loc;
string *m_name;
+
+private:
fields *m_fields;
};
@@ -1019,6 +1119,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; }
@@ -1066,6 +1173,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:
@@ -1188,7 +1302,8 @@ public:
m_link_section (NULL),
m_reg_name (NULL),
m_tls_model (GCC_JIT_TLS_MODEL_NONE),
- m_alignment (0)
+ m_alignment (0),
+ m_attributes ()
{}
playback::lvalue *
@@ -1208,6 +1323,14 @@ public:
as_rvalue () { return this; }
const char *access_as_rvalue (reproducer &r) override;
+
+ void set_readonly ()
+ {
+ m_readonly = true;
+ }
+
+ void add_attribute (gcc_jit_variable_attribute attribute, const char* value);
+
virtual const char *access_as_lvalue (reproducer &r);
virtual bool is_global () const { return false; }
void set_tls_model (enum gcc_jit_tls_model model);
@@ -1221,6 +1344,8 @@ protected:
string *m_reg_name;
enum gcc_jit_tls_model m_tls_model;
unsigned m_alignment;
+ bool m_readonly = false;
+ std::vector> m_attributes;
};
class param : public lvalue
@@ -1274,7 +1399,8 @@ public:
int num_params,
param **params,
int is_variadic,
- enum built_in_function builtin_id);
+ enum built_in_function builtin_id,
+ int is_target_builtin);
void replay_into (replayer *r) final override;
@@ -1308,11 +1434,17 @@ public:
void write_to_dump (dump &d) final override;
+ bool is_target_builtin () const { return m_is_target_builtin; }
+
void validate ();
void dump_to_dot (const char *path);
rvalue *get_address (location *loc);
+ void set_personality_function (function *function);
+
+ void add_attribute (gcc_jit_fn_attribute attribute);
+ void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value);
private:
string * make_debug_string () final override;
@@ -1329,6 +1461,9 @@ private:
auto_vec m_locals;
auto_vec m_blocks;
type *m_fn_ptr_type;
+ std::vector m_attributes;
+ std::vector> m_string_attributes;
+ int m_is_target_builtin;
};
class block : public memento
@@ -1357,6 +1492,12 @@ public:
add_eval (location *loc,
rvalue *rvalue);
+ statement *
+ add_try_catch (location *loc,
+ block *try_block,
+ block *catch_block,
+ bool is_finally = false);
+
statement *
add_assignment (location *loc,
lvalue *lvalue,
@@ -1572,6 +1713,27 @@ private:
string *m_value;
};
+class memento_of_set_personality_function : public memento
+{
+public:
+ memento_of_set_personality_function (context *ctx,
+ function *func,
+ function *personality_function)
+ : memento(ctx),
+ m_function (func),
+ m_personality_function (personality_function) {}
+
+ void replay_into (replayer *r) final override;
+
+private:
+ string * make_debug_string () final override;
+ void write_reproducer (reproducer &r) final override;
+
+private:
+ function *m_function;
+ function *m_personality_function;
+};
+
class memento_of_new_rvalue_from_vector : public rvalue
{
public:
@@ -1597,6 +1759,33 @@ private:
auto_vec m_elements;
};
+class memento_of_new_rvalue_vector_perm : public rvalue
+{
+public:
+ memento_of_new_rvalue_vector_perm (context *ctxt,
+ location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask);
+
+ void replay_into (replayer *r) final override;
+
+ void visit_children (rvalue_visitor *) final override;
+
+private:
+ string * make_debug_string () final override;
+ void write_reproducer (reproducer &r) final override;
+ enum precedence get_precedence () const final override
+ {
+ return PRECEDENCE_PRIMARY;
+ }
+
+private:
+ rvalue *m_elements1;
+ rvalue *m_elements2;
+ rvalue *m_mask;
+};
+
class ctor : public rvalue
{
public:
@@ -1879,6 +2068,64 @@ private:
rvalue *m_index;
};
+class convert_vector : public rvalue
+{
+public:
+ convert_vector (context *ctxt,
+ location *loc,
+ rvalue *vector,
+ type *type)
+ : rvalue (ctxt, loc, type),
+ m_vector (vector),
+ m_type (type)
+ {}
+
+ void replay_into (replayer *r) final override;
+
+ void visit_children (rvalue_visitor *v) final override;
+
+private:
+ string * make_debug_string () final override;
+ void write_reproducer (reproducer &r) final override;
+ enum precedence get_precedence () const final override
+ {
+ return PRECEDENCE_POSTFIX;
+ }
+
+private:
+ rvalue *m_vector;
+ type *m_type;
+};
+
+class vector_access : public lvalue
+{
+public:
+ vector_access (context *ctxt,
+ location *loc,
+ rvalue *vector,
+ rvalue *index)
+ : lvalue (ctxt, loc, vector->get_type ()->dyn_cast_vector_type ()->get_element_type ()),
+ m_vector (vector),
+ m_index (index)
+ {}
+
+ void replay_into (replayer *r) final override;
+
+ void visit_children (rvalue_visitor *v) final override;
+
+private:
+ string * make_debug_string () final override;
+ void write_reproducer (reproducer &r) final override;
+ enum precedence get_precedence () const final override
+ {
+ return PRECEDENCE_POSTFIX;
+ }
+
+private:
+ rvalue *m_vector;
+ rvalue *m_index;
+};
+
class access_field_of_lvalue : public lvalue
{
public:
@@ -2119,6 +2366,31 @@ private:
rvalue *m_rvalue;
};
+class try_catch : public statement
+{
+public:
+ try_catch (block *b,
+ location *loc,
+ block *try_block,
+ block *catch_block,
+ bool is_finally = false)
+ : statement (b, loc),
+ m_try_block (try_block),
+ m_catch_block (catch_block),
+ m_is_finally (is_finally) {}
+
+ void replay_into (replayer *r) final override;
+
+private:
+ string * make_debug_string () final override;
+ void write_reproducer (reproducer &r) final override;
+
+private:
+ block *m_try_block;
+ block *m_catch_block;
+ bool m_is_finally;
+};
+
class assignment : public statement
{
public:
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
+ . */
+
+#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..ad41376fa7f
--- /dev/null
+++ b/gcc/jit/jit-target.cc
@@ -0,0 +1,94 @@
+/* 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
+. */
+
+#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
+
+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 (const char* 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::~target_info()
+{
+ free (const_cast ((const void *) m_arch));
+}
+
+target_info *
+jit_get_target_info ()
+{
+ target_info *info = new target_info {std::move(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..92648ac25d8
--- /dev/null
+++ b/gcc/jit/jit-target.def
@@ -0,0 +1,70 @@
+/* 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
+ . */
+
+/* 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_"
+
+/* Environmental version identifiers relating to the target CPU. */
+DEFHOOK
+(jit_cpu_versions,
+ "Declare all environmental version identifiers relating to the target CPU\n\
+using the function @code{builtin_version}, which takes a string representing\n\
+the name of the version. Version identifiers predefined by this hook apply\n\
+to all modules that are being compiled and imported.",
+ void, (void),
+ hook_void_void)
+
+/* Environmental version identifiers relating to the target OS. */
+DEFHOOK
+(jit_os_versions,
+ "Similarly to @code{TARGET_JIT_CPU_VERSIONS}, but is used for versions\n\
+relating to the target operating system.",
+ void, (void),
+ hook_void_void)
+
+/* 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 keys\n\
+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..09fd7941c2e
--- /dev/null
+++ b/gcc/jit/jit-target.h
@@ -0,0 +1,70 @@
+/* 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
+ . */
+
+#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
+#include
+
+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:
+ ~target_info();
+
+ bool has_target_value (const char *key, const char *value);
+
+ std::unordered_map, CStringHash, CStringEqual> m_info;
+ const char *m_arch = nullptr;
+ 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 (const char* 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 8884128e8d8..050e68b738c 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
{
};
@@ -592,6 +597,20 @@ gcc_jit_type_is_pointer (gcc_jit_type *type)
return (gcc_jit_type *)type->is_pointer ();
}
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::type::is_const method, in
+ jit-recording.cc. */
+
+gcc_jit_type *
+gcc_jit_type_is_const (gcc_jit_type *type)
+{
+ RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+ return (gcc_jit_type *)type->is_const ();
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
@@ -751,7 +770,7 @@ gcc_jit_type *
gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
gcc_jit_location *loc,
gcc_jit_type *element_type,
- int num_elements)
+ unsigned long num_elements)
{
RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
JIT_LOG_FUNC (ctxt->get_logger ());
@@ -783,12 +802,13 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
/* LOC can be NULL. */
RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
- RETURN_NULL_IF_FAIL_PRINTF2 (
+ // TODO: check at playback if the size is known.
+ /*RETURN_NULL_IF_FAIL_PRINTF2 (
type->has_known_size (),
ctxt, loc,
"unknown size for field \"%s\" (type: %s)",
name,
- type->get_debug_string ());
+ type->get_debug_string ());*/
RETURN_NULL_IF_FAIL_PRINTF1 (
!type->is_void (),
ctxt, loc,
@@ -995,6 +1015,7 @@ size_t
gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type)
{
RETURN_VAL_IF_FAIL (struct_type, 0, NULL, NULL, "NULL struct type");
+ RETURN_VAL_IF_FAIL (struct_type->get_fields (), 0, NULL, NULL, "NULL fields");
return struct_type->get_fields ()->length ();
}
@@ -1745,6 +1766,23 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
reinterpret_cast(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 (ctxt->get_target_builtin_function (name));
+}
+
/* Public entrypoint. See description in libgccjit.h. */
extern gcc_jit_lvalue *
@@ -1853,6 +1891,23 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
return global;
}
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::global::set_readonly method, in
+ jit-recording.cc. */
+
+extern void
+gcc_jit_global_set_readonly (gcc_jit_lvalue *global)
+{
+ RETURN_IF_FAIL (global, NULL, NULL, "NULL global");
+ RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL,
+ "lvalue \"%s\" not a global",
+ global->get_debug_string ());
+
+ global->set_readonly ();
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, this calls the trivial
@@ -2422,6 +2477,8 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt,
/* LOC can be NULL. */
RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+ gcc::jit::recording::vector_type *vector_type = type->dyn_cast_vector_type ();
+ RETURN_NULL_IF_FAIL (vector_type == NULL, ctxt, loc, "cannot cast vector types");
RETURN_NULL_IF_FAIL_PRINTF3 (
is_valid_cast (rvalue->get_type (), type),
ctxt, loc,
@@ -2488,6 +2545,60 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index);
}
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::context::new_convert_vector method in
+ jit-recording.cc. */
+
+gcc_jit_rvalue *
+gcc_jit_context_convert_vector (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *vector,
+ gcc_jit_type *type)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_NULL_IF_FAIL (vector, ctxt, loc, "NULL vector");
+ RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+
+ // TODO: check if the value is a vector.
+ // TODO: check if type is a vector type.
+ // TODO: check if the number of elements in vector and type matches.
+
+ return (gcc_jit_rvalue *)ctxt->new_convert_vector (loc, vector, type);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::context::new_vector_access method in
+ jit-recording.cc. */
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *vector,
+ gcc_jit_rvalue *index)
+{
+ RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index");
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ vector->get_type ()->dyn_cast_vector_type (),
+ ctxt, loc,
+ "vector: %s (type: %s) is not a vector",
+ vector->get_debug_string (),
+ vector->get_type ()->get_debug_string ());
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ index->get_type ()->is_numeric (),
+ ctxt, loc,
+ "index: %s (type: %s) is not of numeric type",
+ index->get_debug_string (),
+ index->get_type ()->get_debug_string ());
+
+ return (gcc_jit_lvalue *)ctxt->new_vector_access (loc, vector, index);
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
@@ -2801,6 +2912,64 @@ gcc_jit_block_add_eval (gcc_jit_block *block,
rvalue->verify_valid_within_stmt (__func__, stmt);
}
+/* Public entrypoint. See description in libgccjit.h.
+ After error-checking, the real work is done by the
+ gcc::jit::recording::block::add_try_catch method in jit-recording.c. */
+
+void
+gcc_jit_block_add_try_catch (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *try_block,
+ gcc_jit_block *catch_block)
+{
+ RETURN_IF_NOT_VALID_BLOCK (block, loc);
+ gcc::jit::recording::context *ctxt = block->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue");
+ RETURN_IF_FAIL (catch_block, ctxt, loc, "NULL rvalue");
+
+ gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, catch_block);
+
+ // TODO: remove this or use it.
+ /* "stmt" should be good enough to be usable in error-messages,
+ but might still not be compilable; perform some more
+ error-checking here. We do this here so that the error messages
+ can contain a stringified version of "stmt", whilst appearing
+ as close as possible to the point of failure. */
+ /*try_block->verify_valid_within_stmt (__func__, stmt);
+ catch_block->verify_valid_within_stmt (__func__, stmt);*/
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+ After error-checking, the real work is done by the
+ gcc::jit::recording::block::add_try_catch method in jit-recording.c. */
+
+void
+gcc_jit_block_add_try_finally (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *try_block,
+ gcc_jit_block *finally_block)
+{
+ RETURN_IF_NOT_VALID_BLOCK (block, loc);
+ gcc::jit::recording::context *ctxt = block->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue");
+ RETURN_IF_FAIL (finally_block, ctxt, loc, "NULL rvalue");
+
+ gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, finally_block, true);
+
+ // TODO: remove this or use it.
+ /* "stmt" should be good enough to be usable in error-messages,
+ but might still not be compilable; perform some more
+ error-checking here. We do this here so that the error messages
+ can contain a stringified version of "stmt", whilst appearing
+ as close as possible to the point of failure. */
+ /*try_block->verify_valid_within_stmt (__func__, stmt);
+ catch_block->verify_valid_within_stmt (__func__, stmt);*/
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
@@ -2821,7 +2990,7 @@ gcc_jit_block_add_assignment (gcc_jit_block *block,
RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
RETURN_IF_FAIL_PRINTF4 (
compatible_types (lvalue->get_type (),
- rvalue->get_type ()),
+ rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL,
ctxt, loc,
"mismatching types:"
" assignment to %s (type: %s) from %s (type: %s)",
@@ -2867,7 +3036,7 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block,
RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
RETURN_IF_FAIL_PRINTF4 (
compatible_types (lvalue->get_type (),
- rvalue->get_type ()),
+ rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL,
ctxt, loc,
"mismatching types:"
" assignment to %s (type: %s) involving %s (type: %s)",
@@ -3575,6 +3744,27 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt,
ctxt->add_command_line_option (optname);
}
+/* Public entrypoint. See description in libgccjit.h.
+ After error-checking, the real work is done by the
+ gcc::jit::recording::function::set_personality_function method, in
+ jit-recording.c. */
+
+void
+gcc_jit_function_set_personality_function (gcc_jit_function *fn,
+ gcc_jit_function *personality_func)
+{
+ RETURN_IF_FAIL (fn, NULL, NULL, "NULL function");
+
+ fn->set_personality_function (personality_func);
+}
+
+extern char* jit_personality_func_name;
+
+void
+gcc_jit_set_global_personality_function_name (char* name) {
+ jit_personality_func_name = name;
+}
+
/* Public entrypoint. See description in libgccjit.h.
The real work is done by the
@@ -3664,6 +3854,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;
+}
+
+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.
@@ -3950,6 +4178,38 @@ gcc_jit_type_get_aligned (gcc_jit_type *type,
return (gcc_jit_type *)type->get_aligned (alignment_in_bytes);
}
+void
+gcc_jit_type_set_packed (gcc_jit_type *type)
+{
+ RETURN_IF_FAIL (type, NULL, NULL, "NULL type");
+
+ type->set_packed ();
+}
+
+void
+gcc_jit_function_add_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute)
+{
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
+
+ func->add_attribute (attribute);
+}
+
+void
+gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const char* value)
+{
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
+
+ func->add_string_attribute (attribute, value);
+}
+
+void
+gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, const char* value)
+{
+ RETURN_IF_FAIL (variable, NULL, NULL, "NULL variable");
+
+ variable->add_attribute (attribute, value);
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
@@ -4056,6 +4316,74 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
(gcc::jit::recording::rvalue **)elements);
}
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::context::new_rvalue_vector_perm method, in
+ jit-recording.cc. */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *elements1,
+ gcc_jit_rvalue *elements2,
+ gcc_jit_rvalue *mask)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL ctxt");
+ JIT_LOG_FUNC (ctxt->get_logger ());
+
+ /* LOC can be NULL. */
+
+ gcc::jit::recording::type *elements1_type = elements1->get_type ();
+ gcc::jit::recording::type *elements2_type = elements2->get_type ();
+ RETURN_NULL_IF_FAIL_PRINTF4 (
+ compatible_types (elements1->get_type ()->unqualified (),
+ elements2->get_type ()->unqualified ()),
+ ctxt, loc,
+ "mismatching types for vector perm:"
+ " elements1: %s (type: %s) elements2: %s (type: %s)",
+ elements1->get_debug_string (),
+ elements1_type->get_debug_string (),
+ elements2->get_debug_string (),
+ elements2_type->get_debug_string ());
+
+ gcc::jit::recording::type *mask_type = mask->get_type ();
+ gcc::jit::recording::vector_type *mask_vector_type = mask_type->dyn_cast_vector_type ();
+ gcc::jit::recording::vector_type *elements1_vector_type = elements1_type->dyn_cast_vector_type ();
+
+ size_t mask_len = mask_vector_type->get_num_units ();
+ size_t elements1_len = elements1_vector_type->get_num_units ();
+
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ mask_len == elements1_len,
+ ctxt, loc,
+ "mismatching length for mask:"
+ " elements1 length: %ld mask length: %ld",
+ mask_len,
+ elements1_len);
+
+ gcc::jit::recording::type *mask_element_type = mask_vector_type->get_element_type ();
+
+ RETURN_NULL_IF_FAIL (
+ mask_element_type->is_int (),
+ ctxt, loc,
+ "elements of mask must be of an integer type");
+
+ gcc::jit::recording::type *elements1_element_type = elements1_vector_type->get_element_type ();
+ size_t mask_element_size = mask_element_type->get_size ();
+ size_t elements1_element_size = elements1_element_type->get_size ();
+
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ mask_element_size == elements1_element_size,
+ ctxt, loc,
+ "mismatching size for mask element type:"
+ " elements1 element type: %ld mask element type: %ld",
+ mask_element_size,
+ elements1_element_size);
+
+ return (gcc_jit_rvalue *)ctxt->new_rvalue_vector_perm(loc, elements1, elements2, mask);
+}
+
/* A mutex around the cached state in parse_basever.
Ideally this would be within parse_basever, but the mutex is only needed
by libgccjit. */
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index b3c389e93f6..9663be4a069 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.
@@ -604,7 +607,9 @@ enum gcc_jit_types
GCC_JIT_TYPE_INT16_T,
GCC_JIT_TYPE_INT32_T,
GCC_JIT_TYPE_INT64_T,
- GCC_JIT_TYPE_INT128_T
+ GCC_JIT_TYPE_INT128_T,
+
+ GCC_JIT_TYPE_BFLOAT16,
};
extern gcc_jit_type *
@@ -652,7 +657,7 @@ extern gcc_jit_type *
gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
gcc_jit_location *loc,
gcc_jit_type *element_type,
- int num_elements);
+ unsigned long num_elements);
/* Struct-handling. */
@@ -1021,6 +1026,12 @@ extern gcc_jit_lvalue *
gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
gcc_jit_rvalue *init_value);
+/* Create a reference to a machine-specific builtin function (sometimes called
+ intrinsic functions). */
+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
@@ -1036,6 +1047,9 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
const void *blob,
size_t num_bytes);
+extern void
+gcc_jit_global_set_readonly (gcc_jit_lvalue *global);
+
/* Upcasting. */
extern gcc_jit_object *
gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
@@ -1292,6 +1306,18 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
gcc_jit_rvalue *ptr,
gcc_jit_rvalue *index);
+extern gcc_jit_rvalue *
+gcc_jit_context_convert_vector (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *vector,
+ gcc_jit_type *type);
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *vector,
+ gcc_jit_rvalue *index);
+
/* Field access is provided separately for both lvalues and rvalues. */
/* Accessing a field of an lvalue of struct type, analogous to:
@@ -1391,6 +1417,38 @@ gcc_jit_block_add_eval (gcc_jit_block *block,
gcc_jit_location *loc,
gcc_jit_rvalue *rvalue);
+/* Add a try/catch statement.
+ This is equivalent to this C++ code:
+ try {
+ try_block
+ }
+ catch (...) {
+ catch_block
+ }
+*/
+
+void
+gcc_jit_block_add_try_catch (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *try_block,
+ gcc_jit_block *catch_block);
+
+/* Add a try/finally statement.
+ This is equivalent to this C++-like code:
+ try {
+ try_block
+ }
+ finally {
+ finally_block
+ }
+*/
+
+void
+gcc_jit_block_add_try_finally (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *try_block,
+ gcc_jit_block *finally_block);
+
/* Add evaluation of an rvalue, assigning the result to the given
lvalue.
@@ -1788,6 +1846,12 @@ extern gcc_jit_rvalue *
gcc_jit_function_get_address (gcc_jit_function *fn,
gcc_jit_location *loc);
+void
+gcc_jit_function_set_personality_function (gcc_jit_function *fn,
+ gcc_jit_function *personality_func);
+
+extern void
+gcc_jit_set_global_personality_function_name (char* name);
#define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
@@ -1806,6 +1870,21 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
size_t num_elements,
gcc_jit_rvalue **elements);
+/* Build a permutation vector rvalue from an 3 arrays of elements.
+
+ "vec_type" should be a vector type, created using gcc_jit_type_get_vector.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_25; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_TARGET_BUILTIN
+*/
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *elements1,
+ gcc_jit_rvalue *elements2,
+ gcc_jit_rvalue *mask);
+
#define LIBGCCJIT_HAVE_gcc_jit_version
/* Functions to retrieve libgccjit version.
@@ -1969,6 +2048,11 @@ gcc_jit_type_is_integral (gcc_jit_type *type);
extern gcc_jit_type *
gcc_jit_type_is_pointer (gcc_jit_type *type);
+/* Return the type behind const type or NULL if it's not a
+ * const type. */
+extern gcc_jit_type *
+gcc_jit_type_is_const (gcc_jit_type *type);
+
/* Given a type, return a dynamic cast to a vector type or NULL. */
extern gcc_jit_vector_type *
gcc_jit_type_dyncast_vector (gcc_jit_type *type);
@@ -1990,6 +2074,59 @@ 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);
+extern gcc_jit_target_info *
+gcc_jit_context_get_target_info (gcc_jit_context *ctxt);
+
+extern void
+gcc_jit_target_info_release (gcc_jit_target_info *info);
+
+extern int
+gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info,
+ const char *feature);
+
+extern const char *
+gcc_jit_target_info_arch (gcc_jit_target_info *info);
+
+extern int
+gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info);
+
+/* Given type "T", get type "T __attribute__ ((packed))". */
+extern void
+gcc_jit_type_set_packed (gcc_jit_type *type);
+
+/* Function attributes. */
+enum gcc_jit_fn_attribute
+{
+ GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE,
+ GCC_JIT_FN_ATTRIBUTE_INLINE,
+ GCC_JIT_FN_ATTRIBUTE_NOINLINE,
+ GCC_JIT_FN_ATTRIBUTE_TARGET,
+ GCC_JIT_FN_ATTRIBUTE_USED,
+ GCC_JIT_FN_ATTRIBUTE_VISIBILITY,
+ GCC_JIT_FN_ATTRIBUTE_COLD,
+ GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE,
+ GCC_JIT_FN_ATTRIBUTE_PURE,
+};
+
+/* Add an attribute to a function. */
+// TODO: also support integer values.
+extern void
+gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute);
+
+extern void
+gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value);
+
+/* Variable attributes. */
+enum gcc_jit_variable_attribute
+{
+ GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY,
+};
+
+/* Add an attribute to a variable. */
+// TODO: also support integer values.
+extern void
+gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, enum gcc_jit_variable_attribute attribute, const char* value);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index cc22b2b414e..e52de0057a5 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -271,3 +271,58 @@ LIBGCCJIT_ABI_24 {
gcc_jit_lvalue_set_alignment;
gcc_jit_lvalue_get_alignment;
} LIBGCCJIT_ABI_23;
+
+LIBGCCJIT_ABI_25 {
+ global:
+ gcc_jit_type_set_packed;
+} LIBGCCJIT_ABI_24;
+
+LIBGCCJIT_ABI_26 {
+ global:
+ gcc_jit_type_is_const;
+} LIBGCCJIT_ABI_25;
+
+LIBGCCJIT_ABI_27 {
+ global:
+ gcc_jit_context_convert_vector;
+} LIBGCCJIT_ABI_26;
+
+LIBGCCJIT_ABI_28 {
+ global:
+ gcc_jit_global_set_readonly;
+} LIBGCCJIT_ABI_27;
+
+LIBGCCJIT_ABI_29 {
+ global:
+ gcc_jit_function_add_attribute;
+ gcc_jit_function_add_string_attribute;
+} LIBGCCJIT_ABI_28;
+
+LIBGCCJIT_ABI_30 {
+ global:
+ gcc_jit_lvalue_add_attribute;
+} LIBGCCJIT_ABI_29;
+
+LIBGCCJIT_ABI_31 {
+ global:
+ gcc_jit_block_add_try_catch;
+ gcc_jit_block_add_try_finally;
+ gcc_jit_function_set_personality_function;
+} LIBGCCJIT_ABI_30;
+
+LIBGCCJIT_ABI_32 {
+ global:
+ gcc_jit_context_get_target_builtin_function;
+ gcc_jit_context_new_rvalue_vector_perm;
+ gcc_jit_context_new_vector_access;
+ gcc_jit_set_global_personality_function_name;
+} LIBGCCJIT_ABI_31;
+
+LIBGCCJIT_ABI_33 {
+ 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_32;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 80606076e78..988e14ae9bc 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -319,6 +319,9 @@
/* test-setting-alignment.c: This can't be in the testcases array as it
is target-specific. */
+/* 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/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index 3568dbb9d63..45a6b25b62b 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -895,8 +895,41 @@ proc jit-verify-assembler-output { args } {
pass "${asm_filename} output pattern test, ${dg-output-text}"
verbose "Passed test for output pattern ${dg-output-text}" 3
}
+}
+
+# Assuming that a .s file has been written out named
+# OUTPUT_FILENAME, check that the argument doesn't match
+# the output file.
+proc jit-verify-assembler-output-not { args } {
+ verbose "jit-verify-assembler: $args"
+
+ set dg-output-text [lindex $args 0]
+ verbose "dg-output-text: ${dg-output-text}"
+ upvar 2 name name
+ verbose "name: $name"
+
+ upvar 2 prog prog
+ verbose "prog: $prog"
+ set asm_filename [jit-get-output-filename $prog]
+ verbose " asm_filename: ${asm_filename}"
+
+ # Read the assembly file.
+ set f [open $asm_filename r]
+ set content [read $f]
+ close $f
+
+ # Verify that the assembly matches the regex.
+ if { [regexp ${dg-output-text} $content] } {
+ fail "${asm_filename} output pattern test, is ${content}, should match ${dg-output-text}"
+ verbose "Failed test for output pattern ${dg-output-text}" 3
+ } else {
+ pass "${asm_filename} output pattern test, ${dg-output-text}"
+ verbose "Passed test for output pattern ${dg-output-text}" 3
+ }
}
+
+
# Assuming that a .o file has been written out named
# OUTPUT_FILENAME, invoke the driver to try to turn it into
# an executable, and try to run the result.
diff --git a/gcc/testsuite/jit.dg/test-cold-attribute.c b/gcc/testsuite/jit.dg/test-cold-attribute.c
new file mode 100644
index 00000000000..8dc7ec5a34b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-cold-attribute.c
@@ -0,0 +1,54 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include
+#include
+
+#include "libgccjit.h"
+
+/* We don't want set_options() in harness.h to set -O2 to see that the cold
+ attribute affects the optimizations. */
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O2".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-cold-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+int
+__attribute__ ((cold))
+t()
+{
+ return -1;
+}
+
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_function *func_t =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "t",
+ 0, NULL,
+ 0);
+ gcc_jit_function_add_attribute(func_t, GCC_JIT_FN_ATTRIBUTE_COLD);
+ gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL);
+ gcc_jit_rvalue *ret = gcc_jit_context_new_rvalue_from_int (ctxt,
+ int_type,
+ -1);
+
+ gcc_jit_block_end_with_return (block, NULL, ret);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* { dg-final { jit-verify-assembler-output "orl" } } */
diff --git a/gcc/testsuite/jit.dg/test-pure-attribute.c b/gcc/testsuite/jit.dg/test-pure-attribute.c
new file mode 100644
index 00000000000..049c495faac
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-pure-attribute.c
@@ -0,0 +1,134 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include
+#include
+
+#include "libgccjit.h"
+
+/* We don't want set_options() in harness.h to set -O3 to see that the cold
+ attribute affects the optimizations. */
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ // Set "-O3".
+ gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME "output-of-test-pure-attribute.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+__attribute__ ((pure))
+int foo (int x);
+int xxx(void)
+{
+ int x = 45;
+ int sum = 0;
+
+ while (x >>= 1)
+ sum += foo (x) * 2;
+ return sum;
+}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Creating the `foo` function. */
+ gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "x");
+ gcc_jit_param *params[1] = {n};
+ gcc_jit_function *foo_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ int_type,
+ "foo",
+ 1, params,
+ 0);
+ gcc_jit_function_add_attribute(foo_func, GCC_JIT_FN_ATTRIBUTE_PURE);
+
+ /* Creating the `xxx` function. */
+ gcc_jit_function *xxx_func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "xxx",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL);
+
+ /* Build locals: */
+ gcc_jit_lvalue *x =
+ gcc_jit_function_new_local (xxx_func, NULL, int_type, "x");
+ gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (xxx_func, NULL, int_type, "sum");
+
+ /* int x = 45 */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ x,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 45));
+ /* int sum = 0 */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ sum,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0));
+
+ /* while (x >>= 1) { sum += foo (x) * 2; } */
+ gcc_jit_block *loop_cond =
+ gcc_jit_function_new_block (xxx_func, "loop_cond");
+ gcc_jit_block *loop_body =
+ gcc_jit_function_new_block (xxx_func, "loop_body");
+ gcc_jit_block *after_loop =
+ gcc_jit_function_new_block (xxx_func, "after_loop");
+
+ gcc_jit_block_end_with_jump (block, NULL, loop_cond);
+
+
+ /* if (x >>= 1) */
+ /* Since gccjit doesn't (yet?) have support for `>>=` operator, we will decompose it into:
+ `if (x = x >> 1)` */
+ gcc_jit_block_add_assignment_op (
+ loop_cond, NULL,
+ x,
+ GCC_JIT_BINARY_OP_RSHIFT,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1));
+ /* The condition itself */
+ gcc_jit_block_end_with_conditional (
+ loop_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_NE,
+ gcc_jit_lvalue_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)),
+ after_loop,
+ loop_body);
+
+ /* sum += foo (x) * 2; */
+ gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue(x);
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ x,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, int_type,
+ gcc_jit_context_new_call (ctxt, NULL, foo_func, 1, &arg),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ int_type,
+ 2)));
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
+
+ /* return sum; */
+ gcc_jit_block_end_with_return (after_loop, NULL, gcc_jit_lvalue_as_rvalue(sum));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the loop was optimized away */
+/* { dg-final { jit-verify-assembler-output-not "jne" } } */
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 00000000000..0ffb48e97f6
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-target-builtins.c
@@ -0,0 +1,77 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include
+#include
+
+#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;
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 42937f0ba00..4469e0f069d 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -2332,6 +2332,7 @@ toplev::finalize (void)
cgraphunit_cc_finalize ();
symtab_thunks_cc_finalize ();
dwarf2out_cc_finalize ();
+ dwarf2asm_cc_finalize ();
gcse_cc_finalize ();
ipa_cp_cc_finalize ();
ira_costs_cc_finalize ();
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 78b64ee98b3..ea95e67bb79 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -15006,6 +15006,7 @@ void
tree_cc_finalize (void)
{
clear_nonstandard_integer_type_cache ();
+ gcc_eh_personality_decl = NULL;
}
#if CHECKING_P
diff --git a/gcc/tree.h b/gcc/tree.h
index e730a2a3e56..99695c647fe 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -6479,6 +6479,7 @@ extern tree get_inner_reference (tree, poly_int64_pod *, poly_int64_pod *,
tree *, machine_mode *, int *, int *, int *);
extern tree build_personality_function (const char *);
+extern tree build_personality_function_with_name (const char *);
struct GTY(()) int_n_trees_t {
/* These parts are initialized at runtime */