diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000000000..554d0a790e158
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,59 @@
+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=c,jit,lto --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install/usr --libdir=$(pwd)/../install/usr/lib --libexecdir=$(pwd)/../install/usr/lib
+        make -j4
+        make install
+
+    - name: Build Debian package
+      run: |
+        cd ..
+        mkdir install/DEBIAN
+        cat > install/DEBIAN/control << EOF
+        Package: gcc-13
+        Version: 13
+        Architecture: amd64
+        Maintainer: Antoni Boucher <bouanto@zoho.com>
+        Description: gcc 13 for rustc_codegen_gcc CI
+        EOF
+        dpkg-deb --root-owner-group --build install
+        mv install.deb gcc-13.deb
+
+    - uses: actions/upload-artifact@v3
+      with:
+        name: gcc-13
+        path: /home/runner/work/gcc/gcc-13.deb
+        if-no-files-found: error
+
+    - uses: actions/upload-artifact@v2
+      with:
+          name: libgccjit.so
+          path: |
+            /home/runner/work/gcc/build/gcc/libgccjit.so
+            /home/runner/work/gcc/build/gcc/lto1
+            /home/runner/work/gcc/build/gcc/liblto_plugin.so
+            /home/runner/work/gcc/build/gcc/lto-wrapper
+            /home/runner/work/gcc/build/gcc/crtbeginS.o
+            /home/runner/work/gcc/build/gcc/crtendS.o
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 6aed2cda3cafb..4c092094343c4 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 c4633e869ac06..6a0fc540bcba9 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 0000000000000..6c76c8e0728d0
--- /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
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm_jit.h"
+#include "jit/jit-target.h"
+#include "jit/jit-target-def.h"
+
+/* Do not include tm.h or tm_p.h here; definitions needed by the target
+   architecture to initialize targetjitm should instead be added to tm_jit.h.  */
+
+struct gcc_targetjitm targetjitm = TARGETJITM_INITIALIZER;
diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc
index 01192ef4259a2..37df854ba514b 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 0000000000000..49e54aa799075
--- /dev/null
+++ b/gcc/config/i386/i386-jit.cc
@@ -0,0 +1,212 @@
+/* Subroutines for the JIT front end on the x86 architecture.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tm.h"
+#include "tm_jit.h"
+#include "jit/jit-target.h"
+#include "jit/jit-target-def.h"
+
+/* Implement TARGET_JIT_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* local_cpu = host_detect_local_cpu (2, params);
+  std::string arch = local_cpu;
+  free (const_cast <char *> (local_cpu));
+
+  const char* arg = "-march=";
+  size_t arg_pos = arch.find (arg) + strlen (arg);
+  size_t end_pos = arch.find (" ", arg_pos);
+
+  std::string cpu = arch.substr (arg_pos, end_pos - arg_pos);
+  jit_target_set_arch (cpu);
+
+  jit_target_set_128bit_int_support (targetm.scalar_mode_supported_p (TImode));
+
+  if (TARGET_MMX)
+    jit_add_target_info ("target_feature", "mmx");
+  if (TARGET_SSE)
+    jit_add_target_info("target_feature", "sse");
+  if (TARGET_SSE2)
+    jit_add_target_info("target_feature", "sse2");
+  if (TARGET_SSE3)
+    jit_add_target_info("target_feature", "sse3");
+  if (TARGET_SSSE3)
+    jit_add_target_info("target_feature", "ssse3");
+  if (TARGET_SSE4_1)
+    jit_add_target_info("target_feature", "sse4.1");
+  if (TARGET_SSE4_2)
+    jit_add_target_info("target_feature", "sse4.2");
+  if (TARGET_AES)
+    jit_add_target_info("target_feature", "aes");
+  if (TARGET_SHA)
+    jit_add_target_info("target_feature", "sha");
+  if (TARGET_AVX)
+    jit_add_target_info("target_feature", "avx");
+  if (TARGET_AVX2)
+    jit_add_target_info("target_feature", "avx2");
+  if (TARGET_AVX512F)
+    jit_add_target_info("target_feature", "avx512f");
+  if (TARGET_AVX512ER)
+    jit_add_target_info("target_feature", "avx512er");
+  if (TARGET_AVX512CD)
+    jit_add_target_info("target_feature", "avx512cd");
+  if (TARGET_AVX512PF)
+    jit_add_target_info("target_feature", "avx512pf");
+  if (TARGET_AVX512DQ)
+    jit_add_target_info("target_feature", "avx512dq");
+  if (TARGET_AVX512BW)
+    jit_add_target_info("target_feature", "avx512bw");
+  if (TARGET_AVX512VL)
+    jit_add_target_info("target_feature", "avx512vl");
+  if (TARGET_AVX512VBMI)
+    jit_add_target_info("target_feature", "avx512vbmi");
+  if (TARGET_AVX512IFMA)
+    jit_add_target_info("target_feature", "avx512ifma");
+  if (TARGET_AVX512VPOPCNTDQ)
+    jit_add_target_info("target_feature", "avx512vpopcntdq");
+  if (TARGET_FMA)
+    jit_add_target_info("target_feature", "fma");
+  if (TARGET_RTM)
+    jit_add_target_info("target_feature", "rtm");
+  if (TARGET_SSE4A)
+    jit_add_target_info("target_feature", "sse4a");
+  if (TARGET_BMI) {
+    jit_add_target_info("target_feature", "bmi1");
+    jit_add_target_info("target_feature", "bmi");
+  }
+  if (TARGET_BMI2)
+    jit_add_target_info("target_feature", "bmi2");
+  if (TARGET_LZCNT)
+    jit_add_target_info("target_feature", "lzcnt");
+  if (TARGET_TBM)
+    jit_add_target_info("target_feature", "tbm");
+  if (TARGET_POPCNT)
+    jit_add_target_info("target_feature", "popcnt");
+  if (TARGET_RDRND) {
+    jit_add_target_info("target_feature", "rdrand");
+    jit_add_target_info("target_feature", "rdrnd");
+  }
+  if (TARGET_F16C)
+    jit_add_target_info("target_feature", "f16c");
+  if (TARGET_RDSEED)
+    jit_add_target_info("target_feature", "rdseed");
+  if (TARGET_ADX)
+    jit_add_target_info("target_feature", "adx");
+  if (TARGET_FXSR)
+    jit_add_target_info("target_feature", "fxsr");
+  if (TARGET_XSAVE)
+    jit_add_target_info("target_feature", "xsave");
+  if (TARGET_XSAVEOPT)
+    jit_add_target_info("target_feature", "xsaveopt");
+  if (TARGET_XSAVEC)
+    jit_add_target_info("target_feature", "xsavec");
+  if (TARGET_XSAVES)
+    jit_add_target_info("target_feature", "xsaves");
+  if (TARGET_VPCLMULQDQ) {
+    jit_add_target_info("target_feature", "pclmulqdq");
+    jit_add_target_info("target_feature", "vpclmulqdq");
+  }
+  if (TARGET_CMPXCHG16B)
+    jit_add_target_info("target_feature", "cmpxchg16b");
+  if (TARGET_MOVBE)
+    jit_add_target_info("target_feature", "movbe");
+  if (TARGET_AVX512VBMI2)
+    jit_add_target_info("target_feature", "avx512vbmi2");
+  if (TARGET_PKU)
+    jit_add_target_info("target_feature", "pku");
+  if (TARGET_AVX512VNNI)
+    jit_add_target_info("target_feature", "avx512vnni");
+  if (TARGET_AVX512BF16)
+    jit_add_target_info("target_feature", "avx512bf16");
+  if (TARGET_AVX512BITALG)
+    jit_add_target_info("target_feature", "avx512bitalg");
+  if (TARGET_AVX512VP2INTERSECT)
+    jit_add_target_info("target_feature", "avx512vp2intersect");
+  if (TARGET_PCLMUL)
+    jit_add_target_info("target_feature", "pclmul");
+  if (TARGET_GFNI)
+    jit_add_target_info("target_feature", "gfni");
+  if (TARGET_FMA4)
+    jit_add_target_info("target_feature", "fma4");
+  if (TARGET_XOP)
+    jit_add_target_info("target_feature", "xop");
+
+  // 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 0000000000000..8cfccba405f4c
--- /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
+<http://www.gnu.org/licenses/>.  */
+
+/* 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 ffdbbdfe8cefb..8421b4dba429a 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 0000000000000..20f0d8b4c6567
--- /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
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tm_jit.h"
+#include "jit/jit-target.h"
+#include "jit/jit-target-def.h"
+
+// 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 03966d5ce968c..0be3fb24404d0 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 254f9b6c9430d..dbbc21381d487 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 62bc908b991ff..0513895f7d976 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/doc/tm.texi b/gcc/doc/tm.texi
index 8fe49c2ba3dbb..f6f39b079a879 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -115,6 +115,14 @@ initialize @code{targetdm} themselves, they should set
 @code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default
 definition is used.
 
+Similarly, there is a @code{targetjitm} variable for hooks that are
+specific to the jit front end, documented as ``JIT Target Hook''.
+This is declared in @file{jit/jit-target.h}, the initializer
+@code{TARGETJITM_INITIALIZER} in @file{jit/jit-target-def.h}.  If targets
+initialize @code{targetjitm} themselves, they should set
+@code{target_has_targetjitm=yes} in @file{config.gcc}; otherwise a default
+definition is used.
+
 @node Driver
 @section Controlling the Compilation Driver, @file{gcc}
 @cindex driver
@@ -10902,6 +10910,36 @@ if they have external linkage.  If this flag is false, then instantiated
 decls will be emitted as weak symbols.  The default is @code{false}.
 @end deftypevr
 
+@node JIT Language and ABI
+@section JIT ABI parameters
+@cindex parameters, jit abi
+
+@deftypefn {JIT Target Hook} void TARGET_JIT_CPU_VERSIONS (void)
+Declare all environmental version identifiers relating to the target CPU
+using the function @code{builtin_version}, which takes a string representing
+the name of the version.  Version identifiers predefined by this hook apply
+to all modules that are being compiled and imported.
+@end deftypefn
+
+@deftypefn {JIT Target Hook} void TARGET_JIT_OS_VERSIONS (void)
+Similarly to @code{TARGET_JIT_CPU_VERSIONS}, but is used for versions
+relating to the target operating system.
+@end deftypefn
+
+@deftypefn {JIT Target Hook} void TARGET_JIT_REGISTER_CPU_TARGET_INFO (void)
+Register all target information keys relating to the target CPU using the
+function @code{jit_add_target_info_handlers}, which takes a
+@samp{struct jit_target_info_spec} (defined in @file{jit/jit-target.h}).  The keys
+added by this hook are made available at compile time by the
+@code{__traits(getTargetInfo)} extension, the result is an expression
+describing the requested target information.
+@end deftypefn
+
+@deftypefn {JIT Target Hook} void TARGET_JIT_REGISTER_OS_TARGET_INFO (void)
+Same as @code{TARGET_JIT_CPU_TARGET_INFO}, but is used for keys relating to
+the target operating system.
+@end deftypefn
+
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 62c49ac46de69..b7da440f817a9 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -115,6 +115,14 @@ initialize @code{targetdm} themselves, they should set
 @code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default
 definition is used.
 
+Similarly, there is a @code{targetjitm} variable for hooks that are
+specific to the jit front end, documented as ``JIT Target Hook''.
+This is declared in @file{jit/jit-target.h}, the initializer
+@code{TARGETJITM_INITIALIZER} in @file{jit/jit-target-def.h}.  If targets
+initialize @code{targetjitm} themselves, they should set
+@code{target_has_targetjitm=yes} in @file{config.gcc}; otherwise a default
+definition is used.
+
 @node Driver
 @section Controlling the Compilation Driver, @file{gcc}
 @cindex driver
@@ -7127,6 +7135,18 @@ floating-point support; they are not included in this mechanism.
 
 @hook TARGET_D_TEMPLATES_ALWAYS_COMDAT
 
+@node JIT Language and ABI
+@section JIT ABI parameters
+@cindex parameters, jit abi
+
+@hook TARGET_JIT_CPU_VERSIONS
+
+@hook TARGET_JIT_OS_VERSIONS
+
+@hook TARGET_JIT_REGISTER_CPU_TARGET_INFO
+
+@hook TARGET_JIT_REGISTER_OS_TARGET_INFO
+
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc
index 65b95fee243fb..e66cd30c1fe87 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 37a0a05e5bb1c..80695b3c6c8b3 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 1f39df3b1e250..61b711d4a5269 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 a11f72f606b33..61603c37230c0 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 15be1c8db9991..7fa2c114cb2ff 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 8bcf99292073b..0d4b13b7a71fc 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/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index 63bd525b4c56e..8e0aee01fce48 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -4986,4 +4986,6 @@ void
 ipa_fnsummary_cc_finalize (void)
 {
   ipa_free_fn_summary ();
+  // TODO: this commit contains many fixes that don't necessarily help fixing the bug in the GC. Remove those fixes.
+  ipa_free_size_summary ();
 }
diff --git a/gcc/ipa-icf.cc b/gcc/ipa-icf.cc
index cb9f768d85de6..20d3793574585 100644
--- a/gcc/ipa-icf.cc
+++ b/gcc/ipa-icf.cc
@@ -3656,3 +3656,12 @@ make_pass_ipa_icf (gcc::context *ctxt)
 {
   return new ipa_icf::pass_ipa_icf (ctxt);
 }
+
+/* Reset all state within ipa-icf.cc so that we can rerun the compiler
+   within the same process.  For use by toplev::finalize.  */
+
+void
+ipa_icf_cc_finalize (void)
+{
+  ipa_icf::optimizer = NULL;
+}
diff --git a/gcc/ipa-profile.cc b/gcc/ipa-profile.cc
index 78a40a118bcaa..8083b8195a80b 100644
--- a/gcc/ipa-profile.cc
+++ b/gcc/ipa-profile.cc
@@ -1065,3 +1065,13 @@ make_pass_ipa_profile (gcc::context *ctxt)
 {
   return new pass_ipa_profile (ctxt);
 }
+
+/* Reset all state within ipa-profile.cc so that we can rerun the compiler
+   within the same process.  For use by toplev::finalize.  */
+
+void
+ipa_profile_cc_finalize (void)
+{
+  delete call_sums;
+  call_sums = NULL;
+}
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 16c4b03655820..36b2a104a54f6 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -6001,5 +6001,23 @@ ipcp_transform_function (struct cgraph_node *node)
   return modified_mem_access ? TODO_update_ssa_only_virtuals : 0;
 }
 
+/* Reset all state within ipa-prop.cc so that we can rerun the compiler
+   within the same process.  For use by toplev::finalize.  */
+
+void
+ipa_prop_cc_finalize (void)
+{
+  if (function_insertion_hook_holder)
+    symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
+  function_insertion_hook_holder = NULL;
+
+  if (ipa_edge_args_sum)
+    ggc_delete (ipa_edge_args_sum);
+  ipa_edge_args_sum = NULL;
+
+  if (ipa_node_params_sum)
+    ggc_delete (ipa_node_params_sum);
+  ipa_node_params_sum = NULL;
+}
 
 #include "gt-ipa-prop.h"
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index ea062e00a65b0..10a30d05b947d 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -1162,6 +1162,8 @@ bool ipcp_get_parm_bits (tree, tree *, widest_int *);
 bool unadjusted_ptr_and_unit_offset (tree op, tree *ret,
 				     poly_int64 *offset_ret);
 
+void ipa_prop_cc_finalize (void);
+
 /* From tree-sra.cc:  */
 tree build_ref_for_offset (location_t, tree, poly_int64, bool, tree,
 			   gimple_stmt_iterator *, bool);
diff --git a/gcc/ipa-sra.cc b/gcc/ipa-sra.cc
index 4d7c25c8784af..8a4b17c8c7f53 100644
--- a/gcc/ipa-sra.cc
+++ b/gcc/ipa-sra.cc
@@ -4540,5 +4540,17 @@ make_pass_ipa_sra (gcc::context *ctxt)
   return new pass_ipa_sra (ctxt);
 }
 
+/* Reset all state within ipa-sra.cc so that we can rerun the compiler
+   within the same process.  For use by toplev::finalize.  */
+
+void
+ipa_sra_cc_finalize (void)
+{
+  if (func_sums)
+    ggc_delete (func_sums);
+  func_sums = NULL;
+  delete call_sums;
+  call_sums = NULL;
+}
 
 #include "gt-ipa-sra.h"
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index e7322e1bf4c36..8733ff48cdadd 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -55,6 +55,13 @@ bool ipa_make_function_pure (cgraph_node *, bool, bool);
 
 /* In ipa-profile.cc  */
 bool ipa_propagate_frequency (struct cgraph_node *node);
+void ipa_profile_cc_finalize (void);
+
+/* In ipa-icf.cc  */
+void ipa_icf_cc_finalize (void);
+
+/* In ipa-sra.cc  */
+void ipa_sra_cc_finalize (void);
 
 /* In ipa-devirt.cc  */
 
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
index 248ec45b72953..cca0980b42325 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 0687567bc883d..d3d1b2a120f2f 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,30 +30,47 @@ 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 "cgraph.h"
 
 #include <mpfr.h>
+#include <unordered_map>
+#include <string>
+
+using namespace gcc::jit;
 
 /* Attribute handling.  */
 
-static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
-static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree handle_always_inline_attribute (tree *, tree, tree, int,
+					    bool *);
+static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
 static tree handle_const_attribute (tree *, tree, tree, int, bool *);
+static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+static tree handle_format_attribute (tree *, tree, tree, int, bool *);
+static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
 static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
-static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
-static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
-static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
-static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
-static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
-static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
 static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
 						       int, bool *);
-static tree ignore_attribute (tree *, tree, tree, int, bool *);
+static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
+static tree handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree handle_used_attribute (tree *, tree, tree, int, bool *);
+static tree handle_visibility_attribute (tree *, tree, tree, int,
+					 bool *);
+static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
 
-static tree handle_format_attribute (tree *, tree, tree, int, bool *);
-static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
-static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+static tree ignore_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
 #define ATTR_EXCL(name, function, type, variable)	\
@@ -81,32 +99,70 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
 static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
 {
   ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("alloc_align", true, true, true),
+  ATTR_EXCL ("alloc_size", true, true, true),
+  ATTR_EXCL ("malloc", true, true, true),
   ATTR_EXCL ("noreturn", true, true, true),
   ATTR_EXCL ("pure", true, true, true),
   ATTR_EXCL (NULL, false, false, false)
 };
 
+static const struct attribute_spec::exclusions attr_inline_exclusions[] =
+{
+  ATTR_EXCL ("noinline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+{
+  ATTR_EXCL ("cold", true, true, true),
+  ATTR_EXCL ("hot", true, true, true),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
+static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
+{
+  ATTR_EXCL ("always_inline", true, true, true),
+  ATTR_EXCL ("gnu_inline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+hash_map<nofree_string_hash, tree> target_builtins{};
+std::unordered_map<std::string, recording::function_type*> target_function_types{};
+recording::context target_builtins_ctxt{NULL};
+
 /* Table of machine-independent attributes supported in libgccjit.  */
 const struct attribute_spec jit_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
        affects_type_identity, handler, exclude } */
-  { "noreturn",               0, 0, true,  false, false, false,
-			      handle_noreturn_attribute,
-			      attr_noreturn_exclusions },
-  { "leaf",		      0, 0, true,  false, false, false,
-			      handle_leaf_attribute, NULL },
+  { "alias",                  1, 1, true,  false, false, false,
+			      handle_alias_attribute, NULL },
+  { "always_inline",          0, 0, true,  false, false, false,
+			      handle_always_inline_attribute,
+			      attr_inline_exclusions },
+  { "cold",                   0, 0, true,  false, false, false,
+			      handle_cold_attribute,
+			      attr_cold_hot_exclusions },
   /* The same comments as for noreturn attributes apply to const ones.  */
   { "const",                  0, 0, true,  false, false, false,
 			      handle_const_attribute,
 			      attr_const_pure_exclusions },
+  { "fn spec",	 	      1, 1, false, true, true, false,
+			      handle_fnspec_attribute, NULL },
+
+  { "leaf",		      0, 0, true,  false, false, false,
+			      handle_leaf_attribute, NULL },
   { "malloc",                 0, 0, true,  false, false, false,
 			      handle_malloc_attribute, NULL },
-  { "pure",                   0, 0, true,  false, false, false,
-			      handle_pure_attribute,
-			      attr_const_pure_exclusions },
+  { "noreturn",               0, 0, true,  false, false, false,
+			      handle_noreturn_attribute,
+			      attr_noreturn_exclusions },
   { "no vops",                0, 0, true,  false, false, false,
 			      handle_novops_attribute, NULL },
+  { "noinline",               0, 0, true,  false, false, false,
+			      handle_noinline_attribute,
+			      attr_noinline_exclusions },
   { "nonnull",                0, -1, false, true, true, false,
 			      handle_nonnull_attribute, NULL },
   { "nothrow",                0, 0, true,  false, false, false,
@@ -114,21 +170,30 @@ const struct attribute_spec jit_attribute_table[] =
   { "patchable_function_entry", 1, 2, true, false, false, false,
 			      handle_patchable_function_entry_attribute,
 			      NULL },
+  { "pure",                   0, 0, true,  false, false, false,
+			      handle_pure_attribute,
+			      attr_const_pure_exclusions },
   { "returns_twice",          0, 0, true,  false, false, false,
 			      handle_returns_twice_attribute,
 			      attr_returns_twice_exclusions },
   { "sentinel",               0, 1, false, true, true, false,
 			      handle_sentinel_attribute, NULL },
+  { "target",                 1, -1, true, false, false, false,
+			      handle_target_attribute, NULL },
   { "type generic",           0, 0, false, true, true, false,
 			      handle_type_generic_attribute, NULL },
-  { "fn spec",	 	      1, 1, false, true, true, false,
-			      handle_fnspec_attribute, NULL },
   { "transaction_pure",	      0, 0, false, true, true, false,
 			      handle_transaction_pure_attribute, NULL },
   /* For internal use only.  The leading '*' both prevents its usage in
      source code and signals that it may be overridden by machine tables.  */
   { "*tm regparm",            0, 0, false, true, true, false,
 			      ignore_attribute, NULL },
+  { "used",                   0, 0, true,  false, false, false,
+			      handle_used_attribute, NULL },
+  { "visibility",           1, 1, false, false, false, false,
+			      handle_visibility_attribute, NULL },
+  { "weak",                   0, 0, true,  false, false, false,
+			      handle_weak_attribute, NULL },
   { NULL,                     0, 0, false, false, false, false, NULL, NULL }
 };
 
@@ -146,6 +211,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
@@ -202,10 +281,6 @@ handle_const_attribute (tree *node, tree ARG_UNUSED (name),
 			tree ARG_UNUSED (args), int ARG_UNUSED (flags),
 			bool * ARG_UNUSED (no_add_attrs))
 {
-  if (TREE_CODE (*node) != FUNCTION_DECL
-      || !fndecl_built_in_p (*node))
-    inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name);
-
   tree type = TREE_TYPE (*node);
 
   /* See FIXME comment on noreturn in c_common_attribute_table.  */
@@ -480,6 +555,385 @@ handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
+/* Handle an "visibility" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_visibility_attribute (tree *node, tree name, tree args,
+			     int ARG_UNUSED (flags),
+			     bool *ARG_UNUSED (no_add_attrs))
+{
+  tree decl = *node;
+  tree id = TREE_VALUE (args);
+  enum symbol_visibility vis;
+
+  if (TYPE_P (*node))
+    {
+      if (TREE_CODE (*node) == ENUMERAL_TYPE)
+	/* OK */;
+      else if (!RECORD_OR_UNION_TYPE_P (*node))
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
+		   name);
+	  return NULL_TREE;
+	}
+      else if (TYPE_FIELDS (*node))
+	{
+	  error ("%qE attribute ignored because %qT is already defined",
+		 name, *node);
+	  return NULL_TREE;
+	}
+    }
+  else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (id) != STRING_CST)
+    {
+      error ("visibility argument not a string");
+      return NULL_TREE;
+    }
+
+  /*  If this is a type, set the visibility on the type decl.  */
+  if (TYPE_P (decl))
+    {
+      decl = TYPE_NAME (decl);
+      if (!decl)
+	return NULL_TREE;
+      if (TREE_CODE (decl) == IDENTIFIER_NODE)
+	{
+	   warning (OPT_Wattributes, "%qE attribute ignored on types",
+		    name);
+	   return NULL_TREE;
+	}
+    }
+
+  if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
+    vis = VISIBILITY_DEFAULT;
+  else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
+    vis = VISIBILITY_INTERNAL;
+  else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
+    vis = VISIBILITY_HIDDEN;
+  else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
+    vis = VISIBILITY_PROTECTED;
+  else
+    {
+      error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs",
+	     name, "default", "hidden", "protected", "internal");
+      vis = VISIBILITY_DEFAULT;
+    }
+
+  if (DECL_VISIBILITY_SPECIFIED (decl)
+      && vis != DECL_VISIBILITY (decl))
+    {
+      tree attributes = (TYPE_P (*node)
+			 ? TYPE_ATTRIBUTES (*node)
+			 : DECL_ATTRIBUTES (decl));
+      if (lookup_attribute ("visibility", attributes))
+	error ("%qD redeclared with different visibility", decl);
+      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+	       && lookup_attribute ("dllimport", attributes))
+	error ("%qD was declared %qs which implies default visibility",
+	       decl, "dllimport");
+      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+	       && lookup_attribute ("dllexport", attributes))
+	error ("%qD was declared %qs which implies default visibility",
+	       decl, "dllexport");
+    }
+
+  DECL_VISIBILITY (decl) = vis;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+  /* Go ahead and attach the attribute to the node as well.  This is needed
+     so we can determine whether we have VISIBILITY_DEFAULT because the
+     visibility was not specified, or because it was explicitly overridden
+     from the containing scope.  */
+
+  return NULL_TREE;
+}
+
+/* Handle a "always_inline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_always_inline_attribute (tree *node, tree name,
+				tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags),
+				bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    {
+      if (lookup_attribute ("noinline", DECL_ATTRIBUTES (*node)))
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+		   "with %qs attribute", name, "noinline");
+	  *no_add_attrs = true;
+	}
+      else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+		   "with %qs attribute", name, "target_clones");
+	  *no_add_attrs = true;
+	}
+      else
+	/* Set the attribute and mark it for disregarding inline
+	   limits.  */
+	DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "cold" and attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      || TREE_CODE (*node) == LABEL_DECL)
+    {
+      /* Attribute cold processing is done later with lookup_attribute.  */
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "noinline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_noinline_attribute (tree *node, tree name,
+			   tree ARG_UNUSED (args),
+			   int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    {
+      if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+		   "with attribute %qs", name, "always_inline");
+	  *no_add_attrs = true;
+	}
+      else
+	DECL_UNINLINABLE (*node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "weak" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_weak_attribute (tree *node, tree name,
+		       tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags),
+		       bool * ARG_UNUSED (no_add_attrs))
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && DECL_DECLARED_INLINE_P (*node))
+    {
+      warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
+      *no_add_attrs = true;
+    }
+  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+    {
+      error ("indirect function %q+D cannot be declared weak", *node);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else if (VAR_OR_FUNCTION_DECL_P (*node))
+    declare_weak (*node);
+  else
+    warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+  return NULL_TREE;
+}
+
+/* Handle a "target" attribute.  */
+
+static tree
+handle_target_attribute (tree *node, tree name, tree args, int flags,
+			 bool *no_add_attrs)
+{
+  /* Ensure we have a function type.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+		   "with %qs attribute", name, "target_clones");
+      *no_add_attrs = true;
+    }
+  else if (! targetm.target_option.valid_attribute_p (*node, name, args,
+						      flags))
+    *no_add_attrs = true;
+
+  /* Check that there's no empty string in values of the attribute.  */
+  for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
+    {
+      tree value = TREE_VALUE (t);
+      if (TREE_CODE (value) == STRING_CST
+	  && TREE_STRING_LENGTH (value) == 1
+	  && TREE_STRING_POINTER (value)[0] == '\0')
+	{
+	  warning (OPT_Wattributes, "empty string in attribute %<target%>");
+	  *no_add_attrs = true;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  if (TREE_CODE (node) == FUNCTION_DECL
+      || (VAR_P (node) && TREE_STATIC (node))
+      || (TREE_CODE (node) == TYPE_DECL))
+    {
+      TREE_USED (node) = 1;
+      DECL_PRESERVE_P (node) = 1;
+      if (VAR_P (node))
+	DECL_READ_P (node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler, except that IS_ALIAS tells us
+   whether this is an alias as opposed to ifunc attribute.  */
+
+static tree
+handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
+			      bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      && (!is_alias || !VAR_P (decl)))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+      || (TREE_CODE (decl) != FUNCTION_DECL
+	  && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+      /* A static variable declaration is always a tentative definition,
+	 but the alias is a non-tentative definition which overrides.  */
+      || (TREE_CODE (decl) != FUNCTION_DECL
+	  && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+    {
+      error ("%q+D defined both normally and as %qE attribute", decl, name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else if (!is_alias
+	   && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
+	       || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
+    {
+      error ("weak %q+D cannot be defined %qE", decl, name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Note that the very first time we process a nested declaration,
+     decl_function_context will not be set.  Indeed, *would* never
+     be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
+     we do below.  After such frobbery, pushdecl would set the context.
+     In any case, this is never what we want.  */
+  else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
+    {
+      tree id;
+
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+	{
+	  error ("attribute %qE argument not a string", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+      id = get_identifier (TREE_STRING_POINTER (id));
+      /* This counts as a use of the object pointed to.  */
+      TREE_USED (id) = 1;
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	DECL_INITIAL (decl) = error_mark_node;
+      else
+	TREE_STATIC (decl) = 1;
+
+      if (!is_alias)
+	{
+	  /* ifuncs are also aliases, so set that attribute too.  */
+	  DECL_ATTRIBUTES (decl)
+	    = tree_cons (get_identifier ("alias"), args,
+			 DECL_ATTRIBUTES (decl));
+	  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
+					      NULL, DECL_ATTRIBUTES (decl));
+	}
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  if (decl_in_symtab_p (*node))
+    {
+      struct symtab_node *n = symtab_node::get (decl);
+      if (n && n->refuse_visibility_changes)
+	error ("%+qD declared %qs after being used",
+	       decl, is_alias ? "alias" : "ifunc");
+    }
+
+
+  return NULL_TREE;
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_alias_attribute (tree *node, tree name, tree args,
+			int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
+}
+
 /* (end of attribute-handling).  */
 
 /* Language-dependent contents of a type.  */
@@ -507,12 +961,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 +1032,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 +1048,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 +1134,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 <recording::type *> param_types;
+
+      while (arg != void_list_node)
+      {
+	if (arg == NULL)
+	{
+	  is_variadic = true;
+	  break;
+	}
+	if (arg != void_list_node)
+	{
+	  recording::type* arg_type = tree_type_to_jit_type(TREE_VALUE (arg));
+	  if (arg_type == NULL)
+            return decl;
+	  param_types.safe_push (arg_type);
+	}
+        arg = TREE_CHAIN (arg);
+      }
+
+      tree result_type = TREE_TYPE (function_type);
+      recording::type* return_type = tree_type_to_jit_type(result_type);
+
+      if (return_type == NULL)
+        return decl;
+
+      recording::function_type* func_type = new recording::function_type (&target_builtins_ctxt, return_type, param_types.length (),
+	param_types.address (), is_variadic, false);
+
+      target_function_types[string_name] = func_type;
+    }
+  }
   return decl;
 }
 
@@ -694,6 +1365,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 fb86c77d0fe1c..622a061ea8975 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 3ff7447fbf3f6..5c323411ea953 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 96e9227af40fd..ccb6ebcaa9f19 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<playback::field *> *fields)
+playback::compound_type::set_fields (const auto_vec<playback::field *> *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<playback::field *> *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,50 @@ 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_ALIAS:
+      return "alias";
+    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";
+    case GCC_JIT_FN_ATTRIBUTE_PURE:
+      return "pure";
+    case GCC_JIT_FN_ATTRIBUTE_CONST:
+      return "const";
+    case GCC_JIT_FN_ATTRIBUTE_WEAK:
+      return "weak";
+    case GCC_JIT_FN_ATTRIBUTE_NONNULL:
+      return "nonnull";
+  }
+  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 +565,11 @@ new_function (location *loc,
 	      const char *name,
 	      const auto_vec<param *> *params,
 	      int is_variadic,
-	      enum built_in_function builtin_id)
+	      enum built_in_function builtin_id,
+	      const std::vector<gcc_jit_fn_attribute> &attributes,
+	      const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
+	      const std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> &int_array_attributes,
+	      int is_target_builtin)
 {
   int i;
   param *param;
@@ -532,6 +592,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 +604,16 @@ new_function (location *loc,
   DECL_RESULT (fndecl) = resdecl;
   DECL_CONTEXT (resdecl) = fndecl;
 
+  tree fn_attributes = NULL_TREE;
+
+  if (is_target_builtin)
+  {
+    tree *decl = target_builtins.get(name);
+    if (decl != NULL)
+      fndecl = *decl;
+    else
+      add_error (loc, "cannot find target builtin %s", name);
+  }
   if (builtin_id)
     {
       gcc_assert (loc == NULL);
@@ -588,12 +659,71 @@ new_function (location *loc,
       DECL_DECLARED_INLINE_P (fndecl) = 1;
 
       /* Add attribute "always_inline": */
-      DECL_ATTRIBUTES (fndecl) =
+      fn_attributes =
 	tree_cons (get_identifier ("always_inline"),
 		   NULL,
-		   DECL_ATTRIBUTES (fndecl));
+		   fn_attributes);
+    }
+
+  /* All attributes need to be declared in `dummy-frontend.cc` and more
+     specifically in `jit_attribute_table`. */
+  for (auto attr: attributes)
+  {
+    if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
+    {
+      DECL_DECLARED_INLINE_P (fndecl) = 1;
+      continue;
+    }
+
+    const char* attribute = fn_attribute_to_string (attr);
+    if (attribute)
+    {
+      tree ident = get_identifier (attribute);
+      fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes);
+    }
+  }
+
+  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)
+      fn_attributes = tree_cons (ident, attribute_value, fn_attributes);
+  }
+
+  for (auto attr: int_array_attributes)
+  {
+    gcc_jit_fn_attribute& name = std::get<0>(attr);
+    std::vector<int>& values = std::get<1>(attr);
+
+    const char* attribute = fn_attribute_to_string (name);
+    tree ident = attribute ? get_identifier (attribute) : NULL;
+
+    if (!ident)
+      continue;
+
+    tree tree_list = NULL_TREE;
+    tree *p_tree_list = &tree_list;
+    for (auto value : values)
+    {
+      tree int_value = build_int_cst (integer_type_node, value);
+      *p_tree_list = build_tree_list (NULL, int_value);
+      p_tree_list = &TREE_CHAIN (*p_tree_list);
     }
+    fn_attributes = tree_cons (ident, tree_list, fn_attributes);
+  }
 
+  decl_attributes (&fndecl, fn_attributes, 0);
   function *func = new function (this, fndecl, kind);
   m_functions.safe_push (func);
   return func;
@@ -607,7 +737,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<std::pair<gcc_jit_variable_attribute, std::string>> &attributes)
 {
   gcc_assert (type);
   gcc_assert (name);
@@ -646,15 +778,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<std::pair<gcc_jit_variable_attribute, std::string>> &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 +824,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<std::pair<gcc_jit_variable_attribute, std::string>> &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 +974,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<std::pair<gcc_jit_variable_attribute, std::string>> &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_elt, va_gc> *constructor_elements = NULL;
 
@@ -974,6 +1128,16 @@ new_rvalue_from_const <void *> (type *type,
 
 /* Construct a playback::rvalue instance (wrapping a tree).  */
 
+playback::rvalue *
+playback::context::
+new_sizeof (type *type)
+{
+  tree inner = TYPE_SIZE_UNIT (type->as_tree ());
+  return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
 playback::rvalue *
 playback::context::
 new_string_literal (const char *value)
@@ -1007,10 +1171,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 +1711,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 +2153,8 @@ playback::lvalue *
 playback::function::
 new_local (location *loc,
 	   type *type,
-	   const char *name)
+	   const char *name,
+	   const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes)
 {
   gcc_assert (type);
   gcc_assert (name);
@@ -1825,6 +2167,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 +2201,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 +2228,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 ());
@@ -1947,6 +2305,9 @@ postprocess ()
 
       current_function_decl = NULL;
     }
+    else
+      /* Add to cgraph to output aliases: */
+      rest_of_decl_compilation (m_inner_fndecl, true, 0);
 }
 
 /* Don't leak vec's internal buffer (in non-GC heap) when we are
@@ -1973,6 +2334,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 +3651,7 @@ replay ()
   JIT_LOG_SCOPE (get_logger ());
 
   init_types ();
+  jit_target_init ();
 
   /* Replay the recorded events:  */
   timevar_push (TV_JIT_REPLAY);
@@ -3365,7 +3791,7 @@ void
 playback::context::
 init_types ()
 {
-  /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc 
+  /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
      for reference. If TYPE_NAME is not set, debug info will not contain types */
 #define NAME_TYPE(t,n) \
 if (t) \
@@ -3393,7 +3819,7 @@ if (t) \
   NAME_TYPE (complex_float_type_node, "complex float");
   NAME_TYPE (complex_double_type_node, "complex double");
   NAME_TYPE (complex_long_double_type_node, "complex long double");
-  
+
   m_const_char_ptr = build_pointer_type(
     build_qualified_type (char_type_node, TYPE_QUAL_CONST));
 
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 43e92d67d7426..3ea17e6607126 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 <string>
 #include <utility> // for std::pair
+#include <vector>
 
 #include "timevar.h"
 #include "varasm.h"
@@ -35,17 +37,23 @@ namespace gcc {
 
 namespace jit {
 
+const char* fn_attribute_to_string(gcc_jit_fn_attribute attr);
+
 /**********************************************************************
  Playback.
  **********************************************************************/
 
 namespace playback {
 
+void
+set_variable_attribute(const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &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 +77,7 @@ class context : public log_user
   type *
   new_array_type (location *loc,
 		  type *element_type,
-		  int num_elements);
+		  unsigned long num_elements);
 
   field *
   new_field (location *loc,
@@ -85,7 +93,8 @@ class context : public log_user
   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 +113,20 @@ class context : public log_user
 		const char *name,
 		const auto_vec<param *> *params,
 		int is_variadic,
-		enum built_in_function builtin_id);
+		enum built_in_function builtin_id,
+		const std::vector<gcc_jit_fn_attribute> &attributes,
+		const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
+		const std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> &int_array_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<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
 
   lvalue *
   new_global_initialized (location *loc,
@@ -121,7 +136,9 @@ class context : public log_user
                           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<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
 
   rvalue *
   new_ctor (location *log,
@@ -139,6 +156,9 @@ class context : public log_user
   new_rvalue_from_const (type *type,
 			 HOST_TYPE value);
 
+  rvalue *
+  new_sizeof (type *type);
+
   rvalue *
   new_string_literal (const char *value);
 
@@ -147,6 +167,12 @@ class context : public log_user
 			  type *type,
 			  const auto_vec<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,
@@ -191,6 +217,16 @@ class context : public log_user
 		    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 +342,9 @@ class context : public log_user
                    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<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
   lvalue *
   global_finalize_lvalue (tree inner);
 
@@ -405,6 +443,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.
@@ -446,6 +496,11 @@ class type : public wrapper
     return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
   }
 
+  type *get_restrict () const
+  {
+    return new type (build_qualified_type (m_inner, TYPE_QUAL_RESTRICT));
+  }
+
   type *get_aligned (size_t alignment_in_bytes) const;
   type *get_vector (size_t num_units) const;
 
@@ -460,7 +515,7 @@ class compound_type : public type
     : type (inner)
   {}
 
-  void set_fields (const auto_vec<field *> *fields);
+  void set_fields (const auto_vec<field *> *fields, bool is_packed);
 };
 
 class field : public wrapper
@@ -495,7 +550,8 @@ class function : public wrapper
   lvalue *
   new_local (location *loc,
 	     type *type,
-	     const char *name);
+	     const char *name,
+	     const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
 
   block*
   new_block (const char *name);
@@ -503,6 +559,9 @@ class function : public wrapper
   rvalue *
   get_address (location *loc);
 
+  void
+  set_personality_function (function *personality_function);
+
   void
   build_stmt_list ();
 
@@ -573,6 +632,12 @@ class block : public wrapper
   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 +701,7 @@ class block : public wrapper
 
 public: // for now
   tree m_label_expr;
+  bool m_is_try_or_catch = false;
 
   friend class function;
 };
@@ -813,4 +879,6 @@ extern playback::context *active_playback_ctxt;
 
 } // namespace gcc
 
+extern hash_map<nofree_string_hash, tree> target_builtins;
+
 #endif /* JIT_PLAYBACK_H */
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 2ce272267b817..501ece9d137e0 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<type *>& param_types = func_type->get_param_types ();
+  recording::param **params = new recording::param *[param_types.length ()];
+
+  int i;
+  recording::type *param_type;
+  FOR_EACH_VEC_ELT (param_types, i, param_type)
+    {
+      char buf[16];
+      snprintf (buf, 16, "arg%d", i);
+      params[i] = new_param (NULL,
+			     param_type,
+			     buf);
+  }
+
+  recording::function *result =
+    new recording::function (this,
+                 NULL,
+                 GCC_JIT_FUNCTION_IMPORTED, // 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.
 
@@ -1076,6 +1125,21 @@ recording::context::new_global_init_rvalue (lvalue *variable,
   gbl->set_rvalue_init (init); /* Needed by the global for write dump.  */
 }
 
+/* Create a recording::memento_of_sizeof instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_sizeof.  */
+
+recording::rvalue *
+recording::context::new_sizeof (recording::type *type)
+{
+  recording::rvalue *result =
+    new memento_of_new_sizeof (this, NULL, type);
+  record (result);
+  return result;
+}
+
 /* Create a recording::memento_of_new_string_literal instance and add it
    to this context's list of mementos.
 
@@ -1108,6 +1172,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 +1385,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 +1634,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.  */
 
@@ -2267,6 +2395,19 @@ recording::type::get_const ()
   return result;
 }
 
+/* Given a type T, get the type restrict T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_restrict.  */
+
+recording::type *
+recording::type::get_restrict ()
+{
+  recording::type *result = new memento_of_get_restrict (this);
+  m_ctxt->record (result);
+  return result;
+}
+
 /* Given a type T, get the type volatile T.
 
    Implements the post-error-checking part of
@@ -2294,6 +2435,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 +2519,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 +2582,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 +2647,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 +2706,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 +2766,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 +2830,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 +2910,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 +2957,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
@@ -2960,6 +3118,40 @@ recording::memento_of_get_volatile::write_reproducer (reproducer &r)
 	   r.get_identifier_as_type (m_other_type));
 }
 
+/* The implementation of class gcc::jit::recording::memento_of_get_restrict.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_restrict.  */
+
+void
+recording::memento_of_get_restrict::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_restrict ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_restrict, prepending "restrict ".  */
+
+recording::string *
+recording::memento_of_get_restrict::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "restrict %s", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for restrict
+   types.  */
+
+void
+recording::memento_of_get_restrict::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_restrict (%s);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type));
+}
+
 /* The implementation of class gcc::jit::recording::memento_of_get_aligned.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -3066,7 +3258,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 +3274,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 +3290,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 +3678,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 +3733,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 +3805,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 +4175,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 +4245,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 +4257,11 @@ 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_int_array_attributes(),
+  m_is_target_builtin (is_target_builtin)
 {
   for (int i = 0; i< num_params; i++)
     {
@@ -4114,7 +4320,41 @@ recording::function::replay_into (replayer *r)
 				     m_name->c_str (),
 				     &params,
 				     m_is_variadic,
-				     m_builtin_id));
+				     m_builtin_id,
+				     m_attributes,
+				     m_string_attributes,
+				     m_int_array_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
@@ -4163,6 +4403,40 @@ recording::function::new_block (const char *name)
 void
 recording::function::write_to_dump (dump &d)
 {
+  for (auto attr: m_attributes)
+  {
+    const char* attribute = fn_attribute_to_string (attr);
+    if (attribute)
+      d.write("__attribute(%s)__\n", attribute);
+  }
+  for (auto attr: m_string_attributes)
+  {
+    gcc_jit_fn_attribute& name = std::get<0>(attr);
+    std::string& value = std::get<1>(attr);
+    const char* attribute = fn_attribute_to_string (name);
+
+    if (attribute)
+      d.write("__attribute(%s(\"%s\"))__\n", attribute, value.c_str());
+  }
+  for (auto attr: m_int_array_attributes)
+  {
+    gcc_jit_fn_attribute& name = std::get<0>(attr);
+    std::vector<int>& values = std::get<1>(attr);
+    const char* attribute = fn_attribute_to_string (name);
+    if (attribute)
+    {
+      d.write("__attribute(%s(", attribute);
+      for (int i = 0; i < values.size(); ++i)
+      {
+	if (i > 0)
+	  d.write(", %d", values[i]);
+	else
+	  d.write("%d", values[i]);
+      }
+      d.write("))__\n");
+    }
+  }
+
   switch (m_kind)
     {
     default: gcc_unreachable ();
@@ -4259,6 +4533,13 @@ recording::function::validate ()
       /* Iteratively walk the graph of blocks, marking their "m_is_reachable"
 	 flag, starting at the initial block.  */
       auto_vec<block *> 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 +4628,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 +4639,24 @@ 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)));
+}
+
+void
+recording::function::add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length)
+{
+  m_int_array_attributes.push_back (std::make_pair (attribute, std::vector<int> (value, value + length)));
+}
+
 /* Implementation of recording::memento::make_debug_string for
    functions.  */
 
@@ -4441,6 +4741,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 +5157,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]);
@@ -5263,6 +5592,43 @@ memento_of_new_rvalue_from_const <void *>::write_reproducer (reproducer &r)
 
 } // namespace recording
 
+/* The implementation of class gcc::jit::recording::memento_of_new_sizeof.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_sizeof.  */
+
+void
+recording::memento_of_new_sizeof::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_sizeof (m_type->playback_type ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   sizeof expressions.  */
+
+recording::string *
+recording::memento_of_new_sizeof::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "sizeof (%s)",
+			      m_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for sizeof
+   expressions. */
+
+void
+recording::memento_of_new_sizeof::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_sizeof (%s, /* gcc_jit_context *ctxt */\n"
+    "                                %s); /* gcc_jit_type *type */\n",
+    id,
+    r.get_identifier (get_context ()),
+    m_type->get_debug_string ());
+}
+
 /* The implementation of class gcc::jit::recording::memento_of_new_string_literal.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -5390,6 +5756,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 +6711,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 +7134,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 +7209,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 +7258,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 e1236dec57545..844dae37245ab 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 <string>
+#include <vector>
+
+#include <string>
+#include <unordered_map>
 
 class timer;
 
+extern std::unordered_map<std::string, gcc::jit::recording::function_type*> target_function_types;
+
 namespace gcc {
 
 namespace jit {
-
 extern const char * const unary_op_reproducer_strings[];
 extern const char * const binary_op_reproducer_strings[];
 
@@ -91,7 +99,7 @@ class context : public log_user
   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 @@ class context : public log_user
   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 @@ class context : public log_user
   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,
@@ -165,6 +177,9 @@ class context : public log_user
   new_rvalue_from_const (type *type,
 			 HOST_TYPE value);
 
+  rvalue *
+  new_sizeof (type *type);
+
   rvalue *
   new_string_literal (const char *value);
 
@@ -173,6 +188,12 @@ class context : public log_user
 			  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 +236,16 @@ class context : public log_user
 		    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 +314,9 @@ class context : public log_user
   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);
@@ -524,9 +558,12 @@ class type : public memento
   type *get_pointer ();
   type *get_const ();
   type *get_volatile ();
+  type *get_restrict ();
   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 +576,8 @@ class type : public memento
      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; }
@@ -568,6 +607,7 @@ class type : public memento
   virtual bool is_bool () const = 0;
   virtual type *is_pointer () = 0;
   virtual type *is_volatile () { return NULL; }
+  virtual type *is_restrict () { return NULL; }
   virtual type *is_const () { return NULL; }
   virtual type *is_array () = 0;
   virtual struct_ *is_struct () { return NULL; }
@@ -593,9 +633,13 @@ class type : public memento
 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 +657,11 @@ class memento_of_get_type : public type
 
   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 +713,13 @@ class memento_of_get_pointer : public type
 
   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;
@@ -686,7 +742,7 @@ class memento_of_get_pointer : public type
 };
 
 /* A decorated version of a type, for get_const, get_volatile,
-   get_aligned, and get_vector.  */
+   get_aligned, get_restrict, and get_vector.  */
 
 class decorated_type : public type
 {
@@ -699,6 +755,7 @@ class decorated_type : public type
 
   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 +775,11 @@ class memento_of_get_const : public decorated_type
   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 +815,13 @@ class memento_of_get_volatile : public decorated_type
     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; }
 
@@ -769,6 +834,39 @@ class memento_of_get_volatile : public decorated_type
   void write_reproducer (reproducer &r) final override;
 };
 
+/* Result of "gcc_jit_type_get_restrict".  */
+class memento_of_get_restrict : public decorated_type
+{
+public:
+  memento_of_get_restrict (type *other_type)
+  : decorated_type (other_type) {}
+
+  bool is_same_type_as (type *other) final override
+  {
+    if (!other->is_restrict ())
+      return false;
+    return m_other_type->is_same_type_as (other->is_restrict ());
+  }
+
+  type* copy (context* ctxt) final override
+  {
+    type* result = new memento_of_get_restrict (m_other_type->copy (ctxt));
+    ctxt->record (result);
+    return result;
+  }
+
+  /* Strip off the "restrict", giving the underlying type.  */
+  type *unqualified () final override { return m_other_type; }
+
+  type *is_restrict () final override { return m_other_type; }
+
+  void replay_into (replayer *) final override;
+
+private:
+  string * make_debug_string () final override;
+  void write_reproducer (reproducer &r) final override;
+};
+
 /* Result of "gcc_jit_type_get_aligned".  */
 class memento_of_get_aligned : public decorated_type
 {
@@ -777,11 +875,20 @@ class memento_of_get_aligned : public decorated_type
   : 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 +905,13 @@ class vector_type : public decorated_type
   : 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 +945,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 +954,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 +978,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 +988,8 @@ class function_type : public type
 		 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 +997,18 @@ class function_type : public type
 
   bool is_same_type_as (type *other) final override;
 
+  type* copy(context* ctxt) final override
+  {
+    auto_vec<type *> new_params{};
+    for (size_t i = 0; i < m_param_types.length (); i++)
+      new_params.safe_push (m_param_types[i]->copy (ctxt));
+
+    type* result = new function_type (ctxt, m_return_type->copy (ctxt), m_param_types.length (), new_params.address (),
+      m_is_variadic, m_is_target_builtin);
+    ctxt->record (result);
+    return result;
+  }
+
   bool is_int () const final override { return false; }
   bool is_float () const final override { return false; }
   bool is_bool () const final override { return false; }
@@ -887,6 +1021,7 @@ class function_type : public type
   type * get_return_type () const { return m_return_type; }
   const vec<type *> &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 +1038,7 @@ class function_type : public type
   type *m_return_type;
   auto_vec<type *> m_param_types;
   int m_is_variadic;
+  int m_is_target_builtin;
 };
 
 class field : public memento
@@ -1004,9 +1140,11 @@ class compound_type : public type
     return static_cast <playback::compound_type *> (m_playback_obj);
   }
 
-private:
+protected:
   location *m_loc;
   string *m_name;
+
+private:
   fields *m_fields;
 };
 
@@ -1019,6 +1157,13 @@ class struct_ : public compound_type
 
   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 +1211,13 @@ class union_ : public compound_type
 
   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 +1340,8 @@ class lvalue : public rvalue
     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 +1361,14 @@ class lvalue : public rvalue
   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 +1382,8 @@ class lvalue : public rvalue
   string *m_reg_name;
   enum gcc_jit_tls_model m_tls_model;
   unsigned m_alignment;
+  bool m_readonly = false;
+  std::vector<std::pair<gcc_jit_variable_attribute, std::string>> m_attributes;
 };
 
 class param : public lvalue
@@ -1274,7 +1437,8 @@ class function : public memento
 	    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 +1472,18 @@ class function : public memento
 
   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);
+  void add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length);
 
 private:
   string * make_debug_string () final override;
@@ -1329,6 +1500,10 @@ class function : public memento
   auto_vec<local *> m_locals;
   auto_vec<block *> m_blocks;
   type *m_fn_ptr_type;
+  std::vector<gcc_jit_fn_attribute> m_attributes;
+  std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes;
+  std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> m_int_array_attributes;
+  int m_is_target_builtin;
 };
 
 class block : public memento
@@ -1357,6 +1532,12 @@ class block : public memento
   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,
@@ -1547,6 +1728,31 @@ class memento_of_new_rvalue_from_const : public rvalue
   HOST_TYPE m_value;
 };
 
+class memento_of_new_sizeof : public rvalue
+{
+public:
+  memento_of_new_sizeof (context *ctxt,
+			 location *loc,
+			 type *type)
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_INT)),
+    m_type (type) {}
+
+  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:
+  type *m_type;
+};
+
 class memento_of_new_string_literal : public rvalue
 {
 public:
@@ -1572,6 +1778,27 @@ class memento_of_new_string_literal : public rvalue
   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 +1824,33 @@ class memento_of_new_rvalue_from_vector : public rvalue
   auto_vec<rvalue *> 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 +2133,64 @@ class array_access : public lvalue
   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 +2431,31 @@ class eval : public statement
   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 0000000000000..dcb342fafe7d6
--- /dev/null
+++ b/gcc/jit/jit-target-def.h
@@ -0,0 +1,20 @@
+/* jit-target-def.h -- Default initializers for jit target hooks.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "jit/jit-target-hooks-def.h"
+#include "tree.h"
+#include "hooks.h"
diff --git a/gcc/jit/jit-target.cc b/gcc/jit/jit-target.cc
new file mode 100644
index 0000000000000..671ed24b20f94
--- /dev/null
+++ b/gcc/jit/jit-target.cc
@@ -0,0 +1,89 @@
+/* jit-target.cc -- Target interface for the jit front end.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "tree.h"
+#include "memmodel.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stor-layout.h"
+#include "tm.h"
+#include "tm_p.h"
+#include "target.h"
+#include "calls.h"
+
+#include "jit-target.h"
+
+#include <algorithm>
+
+static target_info jit_target_info;
+
+/* Initialize all variables of the Target structure.  */
+
+void
+jit_target_init ()
+{
+  /* Initialize target info tables, the keys required by the language are added
+     last, so that the OS and CPU handlers can override.  */
+  targetjitm.jit_register_cpu_target_info ();
+  targetjitm.jit_register_os_target_info ();
+}
+
+/* Add all target info in HANDLERS to JIT_TARGET_INFO for use by
+   jit_has_target_value().  */
+
+void
+jit_add_target_info (const char *key, const char *value)
+{
+  if (jit_target_info.m_info.find (key) == jit_target_info.m_info.end())
+    jit_target_info.m_info.insert ({key, {value}});
+  else
+    jit_target_info.m_info[key].insert(value);
+}
+
+void
+jit_target_set_arch (std::string const& arch)
+{
+  jit_target_info.m_arch = arch;
+}
+
+void
+jit_target_set_128bit_int_support (bool support)
+{
+  jit_target_info.m_supports_128bit_int = support;
+}
+
+target_info *
+jit_get_target_info ()
+{
+  target_info *info = new target_info {jit_target_info};
+  jit_target_info = target_info{};
+  return info;
+}
+
+bool
+target_info::has_target_value (const char *key, const char *value)
+{
+  if (m_info.find (key) == m_info.end ())
+    return false;
+
+  auto& set = m_info[key];
+  return set.find (value) != set.end ();
+}
diff --git a/gcc/jit/jit-target.def b/gcc/jit/jit-target.def
new file mode 100644
index 0000000000000..92648ac25d8cf
--- /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
+   <http://www.gnu.org/licenses/>.  */
+
+/* See target-hooks-macros.h for details of macros that should be
+   provided by the including file, and how to use them here.  */
+
+#include "target-hooks-macros.h"
+
+#undef HOOK_TYPE
+#define HOOK_TYPE "JIT Target Hook"
+
+HOOK_VECTOR (TARGETJITM_INITIALIZER, gcc_targetjitm)
+
+#undef HOOK_PREFIX
+#define HOOK_PREFIX "TARGET_"
+
+/* 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 0000000000000..b313faf9cbd52
--- /dev/null
+++ b/gcc/jit/jit-target.h
@@ -0,0 +1,69 @@
+/* jit-target.h -- Data structure definitions for target-specific jit behavior.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_JIT_TARGET_H
+#define GCC_JIT_TARGET_H
+
+#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
+#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS;
+#define DEFHOOK_UNDOC DEFHOOK
+#define HOOKSTRUCT(FRAGMENT) FRAGMENT
+
+#include "jit-target.def"
+
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+static size_t hash_cstr(const char *s)
+{
+  const size_t seed = 0;
+  return std::_Hash_bytes(s, std::strlen(s), seed);
+}
+
+struct CStringHash {
+  size_t operator()(const char* const &string) const {
+    auto res = hash_cstr (string);
+    return res;
+  }
+};
+
+struct CStringEqual {
+  bool operator()(const char* const &string1, const char* const &string2) const {
+      return strcmp (string1, string2) == 0;
+  }
+};
+
+struct target_info {
+  public:
+    bool has_target_value (const char *key, const char *value);
+
+    std::unordered_map<const char *, std::unordered_set<const char *, CStringHash, CStringEqual>, CStringHash, CStringEqual> m_info;
+    std::string m_arch;
+    bool m_supports_128bit_int = false;
+};
+
+/* Each target can provide their own.  */
+extern struct gcc_targetjitm targetjitm;
+
+extern void jit_target_init ();
+extern void jit_target_set_arch (std::string const& arch);
+extern void jit_target_set_128bit_int_support (bool support);
+extern void jit_add_target_info (const char *key, const char *value);
+extern target_info * jit_get_target_info ();
+
+#endif /* GCC_JIT_TARGET_H  */
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 4b88e877bc927..b430f7eb04936 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -1410,6 +1410,12 @@ type::get_const ()
   return type (gcc_jit_type_get_const (get_inner_type ()));
 }
 
+inline type
+type::get_restrict ()
+{
+  return type (gcc_jit_type_get_restrict (get_inner_type ()));
+}
+
 inline type
 type::get_volatile ()
 {
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
index 8884128e8d8ff..8e974f45d1c49 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
 {
 };
@@ -534,6 +539,21 @@ gcc_jit_type_get_volatile (gcc_jit_type *type)
   return (gcc_jit_type *)type->get_volatile ();
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::type::get_restrict method, in
+   jit-recording.cc.  */
+
+gcc_jit_type *
+gcc_jit_type_get_restrict (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+  RETURN_NULL_IF_FAIL (type->is_pointer (), NULL, NULL, "not a pointer type");
+
+  return (gcc_jit_type *)type->get_restrict ();
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -592,6 +612,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 +785,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 +817,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 +1030,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 +1781,23 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
     reinterpret_cast<gcc::jit::recording::rvalue**>(values));
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::get_target_builtin_function method, in
+   jit-recording.c.  */
+
+gcc_jit_function *
+gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt,
+                         const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");
+
+  return static_cast <gcc_jit_function *> (ctxt->get_target_builtin_function (name));
+}
+
 /* Public entrypoint.  See description in libgccjit.h.  */
 
 extern gcc_jit_lvalue *
@@ -1853,6 +1906,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
@@ -2058,6 +2128,23 @@ gcc_jit_context_null (gcc_jit_context *ctxt,
   return gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
 }
 
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_sizeof method in
+   jit-recording.cc.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_sizeof (gcc_jit_context *ctxt,
+			    gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  return ((gcc_jit_rvalue *)ctxt
+	  ->new_sizeof (type));
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -2422,6 +2509,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 +2577,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 +2944,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 +3022,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 +3068,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 +3776,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 +3886,44 @@ gcc_jit_context_compile_to_file (gcc_jit_context *ctxt,
   ctxt->compile_to_file (output_kind, output_path);
 }
 
+gcc_jit_target_info *
+gcc_jit_context_get_target_info (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  ctxt->log ("get_target_info of ctxt: %p", (void *)ctxt);
+
+  ctxt->get_target_info ();
+
+  return (gcc_jit_target_info*) jit_get_target_info ();
+}
+
+void
+gcc_jit_target_info_release (gcc_jit_target_info *info)
+{
+  RETURN_IF_FAIL (info, NULL, NULL, "NULL info");
+  delete info;
+}
+
+int
+gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info,
+				  const char *feature)
+{
+  return info->has_target_value ("target_feature", feature);
+}
+
+const char *
+gcc_jit_target_info_arch (gcc_jit_target_info *info)
+{
+  return info->m_arch.c_str ();
+}
+
+int
+gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info)
+{
+  return info->m_supports_128bit_int;
+}
 
 /* Public entrypoint.  See description in libgccjit.h.
 
@@ -3950,6 +4210,51 @@ 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);
+}
+
+/* This function adds an attribute with multiple integer values. For example
+   `nonnull(1, 2)`. The numbers in `values` are supposed to map how they
+   should be written in C code. So for `nonnull(1, 2)`, you should pass `1`
+   and `2` in `values` (and set `length` to `2`). */
+void
+gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const int* values, size_t length)
+{
+  RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
+  RETURN_IF_FAIL (values, NULL, NULL, "NULL values");
+
+  func->add_integer_array_attribute (attribute, values, length);
+}
+
+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 +4361,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 b3c389e93f68f..273865ca335b9 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 *
@@ -630,6 +635,10 @@ gcc_jit_type_get_const (gcc_jit_type *type);
 extern gcc_jit_type *
 gcc_jit_type_get_volatile (gcc_jit_type *type);
 
+/* Given type "T", get type "restrict T".  */
+extern gcc_jit_type *
+gcc_jit_type_get_restrict (gcc_jit_type *type);
+
 #define LIBGCCJIT_HAVE_SIZED_INTEGERS
 
 /* Given types LTYPE and RTYPE, return non-zero if they are compatible.
@@ -652,7 +661,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 +1030,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 +1051,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);
@@ -1084,6 +1102,10 @@ extern gcc_jit_rvalue *
 gcc_jit_context_null (gcc_jit_context *ctxt,
 		      gcc_jit_type *pointer_type);
 
+extern gcc_jit_rvalue *
+gcc_jit_context_new_sizeof (gcc_jit_context *ctxt,
+			    gcc_jit_type *type);
+
 /* String literals. */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
@@ -1292,6 +1314,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 +1425,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 +1854,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 +1878,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 +2056,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 +2082,65 @@ 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_ALIAS,
+  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,
+  GCC_JIT_FN_ATTRIBUTE_CONST,
+  GCC_JIT_FN_ATTRIBUTE_WEAK,
+  GCC_JIT_FN_ATTRIBUTE_NONNULL,
+};
+
+/* Add an attribute to a function.  */
+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);
+
+extern void
+gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const int* value, size_t length);
+
+/* 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 cc22b2b414e55..f27febaaf1b18 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -271,3 +271,69 @@ 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;
+
+LIBGCCJIT_ABI_34 {
+  global:
+    gcc_jit_type_get_restrict;
+} LIBGCCJIT_ABI_33;
+
+LIBGCCJIT_ABI_35 {
+  global:
+    gcc_jit_context_new_sizeof;
+    gcc_jit_function_add_integer_array_attribute;
+} LIBGCCJIT_ABI_34;
diff --git a/gcc/sort.cc b/gcc/sort.cc
index 9a0113fb62fbe..c7fbd5c51ec09 100644
--- a/gcc/sort.cc
+++ b/gcc/sort.cc
@@ -293,7 +293,8 @@ gcc_sort_r (void *vbase, size_t n, size_t size, sort_r_cmp_fn *cmp, void *data)
   if (buf != scratch)
     free (buf);
 #if CHECKING_P
-  qsort_chk (vbase, n, size, cmp, data);
+  // FIXME: LTO in rustc_codegen_gcc should work even with this check enabled.
+  //qsort_chk (vbase, n, size, cmp, data);
 #endif
 }
 
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 80606076e7870..988e14ae9bcd4 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 3568dbb9d6334..45a6b25b62b69 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 0000000000000..8dc7ec5a34b57
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-cold-attribute.c
@@ -0,0 +1,54 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#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-const-attribute.c b/gcc/testsuite/jit.dg/test-const-attribute.c
new file mode 100644
index 0000000000000..c06742d163f52
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-const-attribute.c
@@ -0,0 +1,134 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+/* We don't want set_options() in harness.h to set -O3 to see that the const
+   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-const-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__ ((const))
+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_CONST);
+
+  /* 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-nonnull.c b/gcc/testsuite/jit.dg/test-nonnull.c
new file mode 100644
index 0000000000000..3306f8906576b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-nonnull.c
@@ -0,0 +1,94 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+/* We don't want set_options() in harness.h to set -O2 to see that the nonnull
+   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-nonnull.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+__attribute__((nonnull(1)))
+int t(int *a) {
+  if (!a) {
+    return -1;
+  }
+  return *a;
+}
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *pint_type = gcc_jit_type_get_pointer(int_type);
+
+  gcc_jit_param *a =
+    gcc_jit_context_new_param (ctxt, NULL, pint_type, "a");
+
+  gcc_jit_function *func_t =
+    gcc_jit_context_new_function (ctxt, NULL,
+	  GCC_JIT_FUNCTION_EXPORTED,
+	  int_type,
+	  "t",
+	  1, &a,
+	  0);
+  /* Adding `nonnull(1)` attribute. */
+  int indexes[1] = {1};
+  gcc_jit_function_add_integer_array_attribute (
+    func_t,
+    GCC_JIT_FN_ATTRIBUTE_NONNULL,
+    indexes,
+    1
+  );
+
+  /* if (!a) {
+    return -1;
+  } */
+  gcc_jit_block *if_cond =
+    gcc_jit_function_new_block (func_t, "if_cond");
+  gcc_jit_block *if_body =
+    gcc_jit_function_new_block (func_t, "if_body");
+  gcc_jit_block *after_if =
+    gcc_jit_function_new_block (func_t, "after_if");
+
+  /* if (!a) */
+  gcc_jit_block_end_with_conditional (
+    if_cond, NULL,
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_EQ,
+      gcc_jit_param_as_rvalue (a),
+      gcc_jit_context_null (ctxt, pint_type)),
+    if_body,
+    after_if);
+  /* return -1; */
+  gcc_jit_block_end_with_return (
+    if_body, NULL,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, -1));
+
+  /* return *a; */
+  gcc_jit_block_end_with_return (
+    after_if, NULL,
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference (
+	gcc_jit_param_as_rvalue (a), NULL)));
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* Check that the "if block" was optimized away */
+/* { dg-final { jit-verify-assembler-output-not "testq" } } */
+/* { dg-final { jit-verify-assembler-output-not "-1" } } */
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 0000000000000..0c9ba1366e0c6
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-pure-attribute.c
@@ -0,0 +1,134 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+/* We don't want set_options() in harness.h to set -O3 to see that the pure
+   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-restrict.c b/gcc/testsuite/jit.dg/test-restrict.c
new file mode 100644
index 0000000000000..4c8c4407f9152
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-restrict.c
@@ -0,0 +1,77 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#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-restrict.c.s"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+	/* Let's try to inject the equivalent of:
+void t(int *__restrict__ a, int *__restrict__ b, char *__restrict__ c) {
+	*a += *c;
+	*b += *c;
+}
+	*/
+	gcc_jit_type *int_type =
+		gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+	gcc_jit_type *pint_type = gcc_jit_type_get_pointer(int_type);
+	gcc_jit_type *pint_restrict_type = gcc_jit_type_get_restrict(pint_type);
+
+	gcc_jit_type *void_type =
+		gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+	gcc_jit_param *a =
+		gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "a");
+	gcc_jit_param *b =
+		gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "b");
+	gcc_jit_param *c =
+		gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "c");
+	gcc_jit_param *params[3] = {a, b, c};
+
+	gcc_jit_function *func_t =
+		gcc_jit_context_new_function (ctxt, NULL,
+					GCC_JIT_FUNCTION_EXPORTED,
+					void_type,
+					"t",
+					3, params,
+					0);
+
+	gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL);
+
+	/* *a += *c; */
+	gcc_jit_block_add_assignment_op (
+		block, NULL,
+		gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (a), NULL),
+		GCC_JIT_BINARY_OP_PLUS,
+		gcc_jit_lvalue_as_rvalue (
+			gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL)));
+	/* *b += *c; */
+	gcc_jit_block_add_assignment_op (
+		block, NULL,
+		gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (b), NULL),
+		GCC_JIT_BINARY_OP_PLUS,
+		gcc_jit_lvalue_as_rvalue (
+			gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL)));
+
+	gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+/* { dg-final { jit-verify-output-file-was-created "" } } */
+/* { dg-final { jit-verify-assembler-output "addl	%eax, (%rdi)
+	addl	%eax, (%rsi)" } } */
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 0000000000000..0ffb48e97f64b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-target-builtins.c
@@ -0,0 +1,77 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  CHECK_NON_NULL (gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_ia32_xgetbv"));
+  gcc_jit_function *builtin_eh_pointer = gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_eh_pointer");
+  CHECK_NON_NULL (builtin_eh_pointer);
+
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *void_ptr =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+  gcc_jit_function *func_main =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  int_type,
+				  "main",
+				  0, NULL,
+				  0);
+  gcc_jit_rvalue *zero = gcc_jit_context_zero (ctxt, int_type);
+  gcc_jit_block *block = gcc_jit_function_new_block (func_main, NULL);
+  gcc_jit_lvalue *variable = gcc_jit_function_new_local(func_main, NULL, void_ptr, "variable");
+  gcc_jit_block_add_assignment (block, NULL, variable,
+    gcc_jit_context_new_call (ctxt, NULL, builtin_eh_pointer, 1, &zero));
+  gcc_jit_block_end_with_return (block, NULL, zero);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+}
+
+int
+main (int argc, char **argv)
+{
+  /*  This is the same as the main provided by harness.h, but it first create a dummy context and compile
+      in order to add the target builtins to libgccjit's internal state.  */
+  gcc_jit_context *ctxt;
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fail ("gcc_jit_context_acquire failed");
+      return -1;
+    }
+  gcc_jit_result *result;
+  result = gcc_jit_context_compile (ctxt);
+  gcc_jit_result_release (result);
+  gcc_jit_context_release (ctxt);
+
+  int i;
+
+  for (i = 1; i <= 5; i++)
+    {
+      snprintf (test, sizeof (test),
+		"%s iteration %d of %d",
+                extract_progname (argv[0]),
+                i, 5);
+
+      //printf ("ITERATION %d\n", i);
+      test_jit (argv[0], NULL);
+      //printf ("\n");
+    }
+
+  totals ();
+
+  return 0;
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 42937f0ba004f..7a379494af35d 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -75,6 +75,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "symbol-summary.h"
 #include "tree-vrp.h"
 #include "ipa-prop.h"
+#include "ipa-utils.h"
 #include "gcse.h"
 #include "omp-offload.h"
 #include "edit-context.h"
@@ -1079,11 +1080,14 @@ general_init (const char *argv0, bool init_signals)
   init_ggc ();
   init_stringpool ();
   input_location = UNKNOWN_LOCATION;
-  line_table = ggc_alloc<line_maps> ();
-  linemap_init (line_table, BUILTINS_LOCATION);
-  line_table->reallocator = realloc_for_line_map;
-  line_table->round_alloc_size = ggc_round_alloc_size;
-  line_table->default_range_bits = 5;
+  if (!line_table)
+  {
+    line_table = ggc_alloc<line_maps> ();
+    linemap_init (line_table, BUILTINS_LOCATION);
+    line_table->reallocator = realloc_for_line_map;
+    line_table->round_alloc_size = ggc_round_alloc_size;
+    line_table->default_range_bits = 5;
+  }
   init_ttree ();
 
   /* Initialize register usage now so switches may override.  */
@@ -2327,11 +2331,16 @@ toplev::finalize (void)
   ipa_fnsummary_cc_finalize ();
   ipa_modref_cc_finalize ();
   ipa_edge_modifications_finalize ();
+  ipa_icf_cc_finalize ();
 
+  ipa_prop_cc_finalize ();
+  ipa_profile_cc_finalize ();
+  ipa_sra_cc_finalize ();
   cgraph_cc_finalize ();
   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 78b64ee98b3e5..ea95e67bb7968 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 e730a2a3e56bd..99695c647fe4a 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 */