changeset 29949:f254c302bb9c

remove JIT compiler from Octave sources As stated in the NEWS file entry added with this changeset, no one has ever seriously taken on further development of the JIT compiler in Octave since it was first added as part of a Google Summer of Code project in 2012 and it still does nothing significant. It is out of date with the default interpreter that walks the parse tree. Even though we have fixed the configure script to disable it by default, people still ask questions about how to build it, but it doesn’t seem that they are doing that to work on it but because they think it will make Octave code run faster (it never did, except for some extremely simple bits of code as examples for demonstration purposes only). * NEWS: Note change. * configure.ac, acinclude.m4: Eliminate checks and macros related to the JIT compiler and LLVM. * basics.txi, install.txi, octave.texi, vectorize.txi: Remove mention of JIT compiler and LLVM. * jit-ir.cc, jit-ir.h, jit-typeinfo.cc, jit-typeinfo.h, jit-util.cc, jit-util.h, pt-jit.cc, pt-jit.h: Delete. * libinterp/parse-tree/module.mk: Update. * Array-jit.cc: Delete. * libinterp/template-inst/module.mk: Update. * test/jit.tst: Delete. * test/module.mk: Update. * interpreter.cc (interpreter::interpreter): Don't check options for debug_jit or jit_compiler. * toplev.cc (F__octave_config_info__): Remove JIT compiler and LLVM info from struct. * ov-base.h (octave_base_value::grab, octave_base_value::release): Delete. * ov-builtin.h, ov-builtin.cc (octave_builtin::to_jit, octave_builtin::stash_jit): Delete. (octave_builtin::m_jtype): Delete data member and all uses. * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_function::m_jit_info): Delete data member and all uses. (octave_user_function::get_info, octave_user_function::stash_info): Delete. * options.h (DEBUG_JIT_OPTION, JIT_COMPILER_OPTION): Delete macro definitions and all uses. * octave.h, octave.cc (cmdline_options::cmdline_options): Don't handle DEBUG_JIT_OPTION, JIT_COMPILER_OPTION): Delete. (cmdline_options::debug_jit, cmdline_options::jit_compiler): Delete functions and all uses. (cmdline_options::m_debug_jit, cmdline_options::m_jit_compiler): Delete data members and all uses. (octave_getopt_options long_opts): Remove "debug-jit" and "jit-compiler" from the list. * pt-eval.cc (tree_evaluator::visit_simple_for_command, tree_evaluator::visit_complex_for_command, tree_evaluator::visit_while_command, tree_evaluator::execute_user_function): Eliminate JIT compiler code. * pt-loop.h, pt-loop.cc (tree_while_command::get_info, tree_while_command::stash_info, tree_simple_for_command::get_info, tree_simple_for_command::stash_info): Delete functions and all uses. (tree_while_command::m_compiled, tree_simple_for_command::m_compiled): Delete member variable and all uses. * usage.h (usage_string, octave_print_verbose_usage_and_exit): Remove [--debug-jit] and [--jit-compiler] from the message. * Array.h (Array<T>::Array): Remove constructor that was only intended to be used by the JIT compiler. (Array<T>::jit_ref_count, Array<T>::jit_slice_data, Array<T>::jit_dimensions, Array<T>::jit_array_rep): Delete. * Marray.h (MArray<T>::MArray): Remove constructor that was only intended to be used by the JIT compiler. * NDArray.h (NDArray::NDarray): Remove constructor that was only intended to be used by the JIT compiler. * dim-vector.h (dim_vector::to_jit): Delete. (dim_vector::dim_vector): Remove constructor that was only intended to be used by the JIT compiler. * codeql-analysis.yaml, make.yaml: Don't require llvm-dev. * subst-config-vals.in.sh, subst-cross-config-vals.in.sh: Don't substitute OCTAVE_CONF_LLVM_CPPFLAGS, OCTAVE_CONF_LLVM_LDFLAGS, or OCTAVE_CONF_LLVM_LIBS. * Doxyfile.in: Don't define HAVE_LLVM. * aspell-octave.en.pws: Eliminate jit, JIT, and LLVM from the list of spelling exceptions. * build-env.h, build-env.in.cc (LLVM_CPPFLAGS, LLVM_LDFLAGS, LLVM_LIBS): Delete variables and all uses. * libinterp/corefcn/module.mk (%canon_reldir%_libcorefcn_la_CPPFLAGS): Remove $(LLVM_CPPFLAGS) from the list. * libinterp/parse-tree/module.mk (%canon_reldir%_libparse_tree_la_CPPFLAGS): Remove $(LLVM_CPPFLAGS) from the list.
author John W. Eaton <jwe@octave.org>
date Tue, 10 Aug 2021 16:42:29 -0400
parents c92a4ebaa777
children 6549fa7558ba
files .github/workflows/codeql-analysis.yaml .github/workflows/make.yaml NEWS build-aux/subst-config-vals.in.sh build-aux/subst-cross-config-vals.in.sh configure.ac doc/doxyhtml/Doxyfile.in doc/interpreter/basics.txi doc/interpreter/doccheck/aspell-octave.en.pws doc/interpreter/install.txi doc/interpreter/octave.texi doc/interpreter/vectorize.txi libinterp/build-env.h libinterp/build-env.in.cc libinterp/corefcn/interpreter.cc libinterp/corefcn/module.mk libinterp/corefcn/toplev.cc libinterp/octave-value/ov-base.h libinterp/octave-value/ov-builtin.cc libinterp/octave-value/ov-builtin.h libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/octave.cc libinterp/octave.h libinterp/options.h libinterp/parse-tree/jit-ir.cc libinterp/parse-tree/jit-ir.h libinterp/parse-tree/jit-typeinfo.cc libinterp/parse-tree/jit-typeinfo.h libinterp/parse-tree/jit-util.cc libinterp/parse-tree/jit-util.h libinterp/parse-tree/module.mk libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-jit.cc libinterp/parse-tree/pt-jit.h libinterp/parse-tree/pt-loop.cc libinterp/parse-tree/pt-loop.h libinterp/template-inst/Array-jit.cc libinterp/template-inst/module.mk libinterp/usage.h liboctave/array/Array.h liboctave/array/MArray.h liboctave/array/dNDArray.h liboctave/array/dim-vector.h m4/acinclude.m4 test/jit.tst test/module.mk
diffstat 47 files changed, 41 insertions(+), 10891 deletions(-) [+]
line wrap: on
line diff
--- a/.github/workflows/codeql-analysis.yaml	Mon Aug 09 16:30:48 2021 +0200
+++ b/.github/workflows/codeql-analysis.yaml	Tue Aug 10 16:42:29 2021 -0400
@@ -34,7 +34,7 @@
             libhdf5-dev liblapack-dev libosmesa6-dev libpcre3-dev \
             libqhull-dev libqscintilla2-qt5-dev libqrupdate-dev \
             libreadline-dev librsvg2-bin libsndfile1-dev libsuitesparse-dev \
-            libsundials-dev libtool libxft-dev llvm-dev make openjdk-8-jdk \
+            libsundials-dev libtool libxft-dev make openjdk-8-jdk \
             perl portaudio19-dev pstoedit qtbase5-dev qttools5-dev \
             qttools5-dev-tools rapidjson-dev rsync tar zlib1g-dev
 
--- a/.github/workflows/make.yaml	Mon Aug 09 16:30:48 2021 +0200
+++ b/.github/workflows/make.yaml	Tue Aug 10 16:42:29 2021 -0400
@@ -49,7 +49,7 @@
             libhdf5-dev liblapack-dev libosmesa6-dev libpcre3-dev \
             libqhull-dev libqscintilla2-qt5-dev libqrupdate-dev \
             libreadline-dev librsvg2-bin libsndfile1-dev libsuitesparse-dev \
-            libsundials-dev libtool libxft-dev llvm-dev make openjdk-8-jdk \
+            libsundials-dev libtool libxft-dev make openjdk-8-jdk \
             perl portaudio19-dev pstoedit qtbase5-dev qttools5-dev \
             qttools5-dev-tools rapidjson-dev rsync tar texinfo \
             texlive-latex-extra xvfb zlib1g-dev
--- a/NEWS	Mon Aug 09 16:30:48 2021 +0200
+++ b/NEWS	Tue Aug 10 16:42:29 2021 -0400
@@ -293,7 +293,7 @@
   work.
 
 
-### Removed functions and properties
+### Removed functions, properties, and features
 
 The following functions and properties were deprecated in Octave 5
 and have been removed from Octave 7.
@@ -315,6 +315,19 @@
   `uipanel`        | `fontangle`   | `"oblique"`
   `uitable`        | `fontangle`   | `"oblique"`
 
+- The prototype JIT compiler has been removed from Octave.  Since it was
+first added as part of a Google Summer of Code project in 2012, no one
+has ever seriously taken on further development of it and it still does
+nothing significant.  It is out of date with the default interpreter
+that walks the parse tree.  Even though we have fixed the configure
+script to disable it by default, people still ask questions about how to
+build it, but it doesn’t seem that they are doing that to work on it but
+because they think it will make Octave code run faster (it never did,
+except for some extremely simple bits of code as examples for
+demonstration purposes only).  The following functions related to the
+JIT compiler have also been removed: `debug_jit`, `jit_enable`,
+`jit_failcnt`, and `jit_startcnt`.
+
 ### Old release news
 
 - [Octave 6.x](etc/NEWS.6)
--- a/build-aux/subst-config-vals.in.sh	Mon Aug 09 16:30:48 2021 +0200
+++ b/build-aux/subst-config-vals.in.sh	Tue Aug 10 16:42:29 2021 -0400
@@ -180,9 +180,6 @@
 LIBOCTAVE="@LIBOCTAVE@"
 LIBOCTINTERP="@LIBOCTINTERP@"
 LIBS="@LIBS@"
-LLVM_CPPFLAGS="@LLVM_CPPFLAGS@"
-LLVM_LDFLAGS="@LLVM_LDFLAGS@"
-LLVM_LIBS="@LLVM_LIBS@"
 LN_S="@LN_S@"
 MAGICK_CPPFLAGS="@MAGICK_CPPFLAGS@"
 MAGICK_LDFLAGS="@MAGICK_LDFLAGS@"
@@ -342,9 +339,6 @@
   -e "s|%OCTAVE_CONF_LIBOCTAVE%|\"${LIBOCTAVE}\"|" \
   -e "s|%OCTAVE_CONF_LIBOCTINTERP%|\"${LIBOCTINTERP}\"|" \
   -e "s|%OCTAVE_CONF_LIBS%|\"${LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_LLVM_CPPFLAGS%|\"${LLVM_CPPFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_LLVM_LDFLAGS%|\"${LLVM_LDFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_LLVM_LIBS%|\"${LLVM_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_LN_S%|\"${LN_S}\"|" \
   -e "s|%OCTAVE_CONF_MAGICK_CPPFLAGS%|\"${MAGICK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_MAGICK_LDFLAGS%|\"${MAGICK_LDFLAGS}\"|" \
--- a/build-aux/subst-cross-config-vals.in.sh	Mon Aug 09 16:30:48 2021 +0200
+++ b/build-aux/subst-cross-config-vals.in.sh	Tue Aug 10 16:42:29 2021 -0400
@@ -190,9 +190,6 @@
 LIBOCTAVE="@LIBOCTAVE@"
 LIBOCTINTERP="@LIBOCTINTERP@"
 LIBS="@LIBS@"
-LLVM_CPPFLAGS="@LLVM_CPPFLAGS@"
-LLVM_LDFLAGS="@LLVM_LDFLAGS@"
-LLVM_LIBS="@LLVM_LIBS@"
 LN_S="@LN_S@"
 MAGICK_CPPFLAGS="@MAGICK_CPPFLAGS@"
 MAGICK_LDFLAGS="@MAGICK_LDFLAGS@"
@@ -346,9 +343,6 @@
   -e "s|%OCTAVE_CONF_LIBOCTAVE%|\"${LIBOCTAVE}\"|" \
   -e "s|%OCTAVE_CONF_LIBOCTINTERP%|\"${LIBOCTINTERP}\"|" \
   -e "s|%OCTAVE_CONF_LIBS%|\"${LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_LLVM_CPPFLAGS%|\"${LLVM_CPPFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_LLVM_LDFLAGS%|\"${LLVM_LDFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_LLVM_LIBS%|\"${LLVM_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_LN_S%|\"${LN_S}\"|" \
   -e "s|%OCTAVE_CONF_MAGICK_CPPFLAGS%|\"${MAGICK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_MAGICK_LDFLAGS%|\"${MAGICK_LDFLAGS}\"|" \
--- a/configure.ac	Mon Aug 09 16:30:48 2021 +0200
+++ b/configure.ac	Tue Aug 10 16:42:29 2021 -0400
@@ -1456,119 +1456,6 @@
   [BZIP2 library not found.  Octave will not be able to compress or decompress bzip2 files.],
   [bzlib.h], [BZ2_bzCompressInit])
 
-### Check for the LLVM library (JIT compiler).
-
-ENABLE_JIT=no
-AC_ARG_ENABLE([jit],
-  [AS_HELP_STRING([--enable-jit],
-    [(EXPERIMENTAL) enable JIT compiler])],
-  [if test "$enableval" = yes; then ENABLE_JIT=yes; fi], [])
-
-LLVM_CPPFLAGS=
-LLVM_LDFLAGS=
-LLVM_LIBS=
-
-if test $ENABLE_JIT = yes; then
-
-  ## Find llvm-config program from environment variable or by searching
-  AC_ARG_VAR([LLVM_CONFIG], [path to llvm-config utility])
-  AC_CHECK_PROG([LLVM_CONFIG], llvm-config, llvm-config, [])
-
-  if test -z "$LLVM_CONFIG"; then
-    warn_llvm="llvm-config utility not found.  JIT compiler is disabled."
-  else
-    dnl Preset warning message in case compile fails
-    warn_llvm="LLVM was not found or is to old.  JIT compiler is disabled."
-
-    save_CPPFLAGS="$CPPFLAGS"
-    save_LDFLAGS="$LDFLAGS"
-
-    dnl Use -isystem if available because we don't want to see warnings in LLVM
-    LLVM_INCLUDE_FLAG=-I
-    OCTAVE_CC_FLAG([-isystem .], [
-      LLVM_INCLUDE_FLAG=-isystem
-      AC_MSG_NOTICE([using -isystem for LLVM headers])])
-
-    dnl Use -isystem so we don't get warnings from llvm headers
-    LLVM_CPPFLAGS="$LLVM_INCLUDE_FLAG `$LLVM_CONFIG --includedir`"
-    LLVM_LDFLAGS="-L`$LLVM_CONFIG --libdir`"
-
-    LDFLAGS="$LDFLAGS $LLVM_LDFLAGS"
-    LLVM_SO=LLVM-`$LLVM_CONFIG --version`
-    AC_CHECK_LIB([$LLVM_SO], [LLVMBuildAdd], [LLVM_LIBS="-l$LLVM_SO"],
-                 [LLVM_LIBS="`$LLVM_CONFIG --libs` `$LLVM_CONFIG --system-libs`"])
-
-    dnl Define some extra flags that LLVM requires in order to include headers.
-    dnl Ideally we should get these from llvm-config, but llvm-config isn't
-    dnl very helpful.
-    CPPFLAGS="-D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS $LLVM_CPPFLAGS $CPPFLAGS"
-    AC_LANG_PUSH(C++)
-    AC_CHECK_HEADER([llvm/Support/TargetSelect.h], [warn_llvm=""])
-
-    have_function_h=no
-    AC_CHECK_HEADERS([llvm/IR/Function.h llvm/Function.h],
-                     [have_function_h=yes; break])
-    if test $have_function_h = no; then
-      warn_llvm="Missing LLVM file Function.h.  JIT compiler is disabled."
-    fi
-
-    have_irbuilder_h=no
-    AC_CHECK_HEADERS([llvm/Support/IRBuilder.h llvm/IR/IRBuilder.h \
-                      llvm/IRBuilder.h], [have_irbuilder_h=yes; break])
-    if test $have_irbuilder_h = no; then
-      warn_llvm="Missing LLVM file IRBuilder.h.  JIT compiler is disabled."
-    fi
-
-    have_llvm_data_h=no
-    AC_CHECK_HEADERS([llvm/Target/TargetData.h llvm/IR/DataLayout.h \
-                      llvm/DataLayout.h], [have_llvm_data_h=yes; break])
-    if test $have_llvm_data_h = no; then
-      warn_llvm="Missing LLVM file TargetData.h.  JIT compiler is disabled."
-    fi
-
-    AC_CHECK_HEADERS([llvm/IR/Verifier.h])
-    AC_CHECK_HEADERS([llvm/Analysis/BasicAliasAnalysis.h])
-    AC_CHECK_HEADERS([llvm/Transforms/Scalar/GVN.h])
-    AC_CHECK_HEADERS([llvm/Bitcode/ReaderWriter.h])
-
-    OCTAVE_LLVM_FUNCTION_ADDATTRIBUTE_API
-    OCTAVE_LLVM_FUNCTION_ADDFNATTR_API
-    OCTAVE_LLVM_CALLINST_ADDATTRIBUTE_API
-    OCTAVE_LLVM_RAW_FD_OSTREAM_API
-    OCTAVE_LLVM_LEGACY_PASSMANAGER_API
-    OCTAVE_LLVM_IRBUILDER_API
-    OCTAVE_LLVM_HAS_CREATEALWAYSINLINERPASS
-    OCTAVE_LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_API
-
-    AC_LANG_POP(C++)
-    CPPFLAGS="$save_CPPFLAGS"
-    LDFLAGS="$save_LDFLAGS"
-  fi
-
-  if test -z "$warn_llvm"; then
-    AC_DEFINE(HAVE_LLVM, 1, [Define to 1 if LLVM is available.])
-  else
-    ENABLE_JIT=no
-    LLVM_CPPFLAGS=
-    LLVM_LDFLAGS=
-    LLVM_LIBS=
-    OCTAVE_CONFIGURE_WARNING([warn_llvm])
-  fi
-dnl FIXME: Re-instate when JIT is enabled by default
-dnl else
-dnl   ## JIT build disabled
-dnl   warn_llvm="JIT compiler disabled, some performance loss for loops"
-dnl   OCTAVE_CONFIGURE_WARNING([warn_llvm])
-fi
-if test $ENABLE_JIT = yes; then
-  AC_DEFINE(ENABLE_JIT, 1, [Define to 1 to enable JIT compiler.])
-fi
-
-AC_SUBST(LLVM_CPPFLAGS)
-AC_SUBST(LLVM_LDFLAGS)
-AC_SUBST(LLVM_LIBS)
-AM_CONDITIONAL([AMCOND_HAVE_LLVM], [test -z "$warn_llvm"])
-
 ### Check for HDF5 library.
 
 save_CPPFLAGS="$CPPFLAGS"
@@ -2966,9 +2853,9 @@
 AC_SUBST(LIBOCTAVE_LINK_DEPS)
 AC_SUBST(LIBOCTAVE_LINK_OPTS)
 
-LIBOCTINTERP_LINK_DEPS="$FT2_LIBS $HDF5_LIBS $MAGICK_LIBS $Z_LIBS $SPARSE_XLIBS $FFTW_XLIBS $OPENGL_LIBS $FONTCONFIG_LIBS $FREETYPE_LIBS $X11_LIBS $CARBON_LIBS $GL2PS_LIBS $LLVM_LIBS $JAVA_LIBS $LAPACK_LIBS"
-
-LIBOCTINTERP_LINK_OPTS="$FT2_LDFLAGS $HDF5_LDFLAGS $MAGICK_LDFLAGS $Z_LDFLAGS $SPARSE_XLDFLAGS $FFTW_XLDFLAGS $LLVM_LDFLAGS"
+LIBOCTINTERP_LINK_DEPS="$FT2_LIBS $HDF5_LIBS $MAGICK_LIBS $Z_LIBS $SPARSE_XLIBS $FFTW_XLIBS $OPENGL_LIBS $FONTCONFIG_LIBS $FREETYPE_LIBS $X11_LIBS $CARBON_LIBS $GL2PS_LIBS $JAVA_LIBS $LAPACK_LIBS"
+
+LIBOCTINTERP_LINK_OPTS="$FT2_LDFLAGS $HDF5_LDFLAGS $MAGICK_LDFLAGS $Z_LDFLAGS $SPARSE_XLDFLAGS $FFTW_XLDFLAGS"
 
 OCTAVE_LINK_DEPS=""
 OCTAVE_LINK_OPTS=""
@@ -3240,9 +3127,6 @@
   KLU LDFLAGS:                   $KLU_LDFLAGS
   KLU libraries:                 $KLU_LIBS
   LAPACK libraries:              $LAPACK_LIBS
-  LLVM CPPFLAGS:                 $LLVM_CPPFLAGS
-  LLVM LDFLAGS:                  $LLVM_LDFLAGS
-  LLVM libraries:                $LLVM_LIBS
   Magick++ CPPFLAGS:             $MAGICK_CPPFLAGS
   Magick++ LDFLAGS:              $MAGICK_LDFLAGS
   Magick++ libraries:            $MAGICK_LIBS
@@ -3302,7 +3186,6 @@
   gnuplot:                       $GNUPLOT_BINARY
 
   Build Octave Qt GUI:                  $BUILD_QT_SUMMARY_MSG
-  JIT compiler for loops:               $ENABLE_JIT
   Build Java interface:                 $build_java
   Build static libraries:               $STATIC_LIBS
   Build shared libraries:               $SHARED_LIBS
--- a/doc/doxyhtml/Doxyfile.in	Mon Aug 09 16:30:48 2021 +0200
+++ b/doc/doxyhtml/Doxyfile.in	Tue Aug 10 16:42:29 2021 -0400
@@ -693,7 +693,6 @@
                          HAVE_GLPK=1 \
                          HAVE_HDF5=1 \
                          HAVE_JAVA=1 \
-                         HAVE_LLVM=1 \
                          HAVE_MAGICK=1 \
                          HAVE_OPENGL=1 \
                          HAVE_OPENMP=1 \
--- a/doc/interpreter/basics.txi	Mon Aug 09 16:30:48 2021 +0200
+++ b/doc/interpreter/basics.txi	Tue Aug 10 16:42:29 2021 -0400
@@ -82,10 +82,6 @@
 parser to print a lot of information about the commands it reads, and is
 probably only useful if you are actually trying to debug the parser.
 
-@item --debug-jit
-@cindex @sortas{options, Octave command --debug-jit} @ @ @code{--debug-jit}
-Enable JIT compiler debugging and tracing.
-
 @item --doc-cache-file @var{filename}
 @cindex @sortas{options, Octave command --doc-cache-file} @ @ @code{--doc-cache-file @var{filename}}
 Specify the name of the doc cache file to use.  The value of @var{filename}
@@ -154,10 +150,6 @@
 Force interactive behavior.  This can be useful for running Octave via a
 remote shell command or inside an Emacs shell buffer.
 
-@item --jit-compiler
-@cindex @sortas{options, Octave command --jit-compiler} @ @ @code{--jit-compiler}
-Enable the JIT compiler used for accelerating loops.
-
 @item --line-editing
 @cindex @sortas{options, Octave command --line-editing} @ @ @code{--line-editing}
 Force readline use for command-line editing.
--- a/doc/interpreter/doccheck/aspell-octave.en.pws	Mon Aug 09 16:30:48 2021 +0200
+++ b/doc/interpreter/doccheck/aspell-octave.en.pws	Tue Aug 10 16:42:29 2021 -0400
@@ -536,8 +536,6 @@
 JConstant
 JDK
 JIS
-jit
-JIT
 JPattern
 jpeg
 JPEG
@@ -590,7 +588,6 @@
 ListSize
 ListString
 literalspacing
-LLVM
 LM
 loadpath
 logarithmically
--- a/doc/interpreter/install.txi	Mon Aug 09 16:30:48 2021 +0200
+++ b/doc/interpreter/install.txi	Tue Aug 10 16:42:29 2021 -0400
@@ -275,11 +275,6 @@
 although other JDK implementations may work.  Java is required to be able
 to call Java functions from within Octave.
 
-@item LLVM
-Compiler framework, (@url{https://www.llvm.org}).  LLVM is required for
-Octave's experimental just-in-time (JIT) compilation for speeding up the
-interpreter.
-
 @item OpenGL
 API for portable 2-D and 3-D graphics (@url{https://www.opengl.org}).  An
 OpenGL implementation can be used to provide a renderer for Octave's
--- a/doc/interpreter/octave.texi	Mon Aug 09 16:30:48 2021 +0200
+++ b/doc/interpreter/octave.texi	Tue Aug 10 16:42:29 2021 -0400
@@ -664,7 +664,6 @@
 * Broadcasting::               Broadcasting operations
 * Function Application::       Applying functions to arrays, cells, and structs
 * Accumulation::               Accumulation functions
-* JIT Compiler::               Just-In-Time Compiler for loops
 * Miscellaneous Techniques::   Other techniques for speeding up code
 * Examples::
 
--- a/doc/interpreter/vectorize.txi	Mon Aug 09 16:30:48 2021 +0200
+++ b/doc/interpreter/vectorize.txi	Tue Aug 10 16:42:29 2021 -0400
@@ -42,7 +42,6 @@
 * Broadcasting::               Broadcasting operations
 * Function Application::       Applying functions to arrays, cells, and structs
 * Accumulation::               Accumulation functions
-* JIT Compiler::               Just-In-Time Compiler for loops
 * Miscellaneous Techniques::   Other techniques for speeding up code
 * Examples::
 @end menu
@@ -506,41 +505,6 @@
 
 @DOCSTRING(accumdim)
 
-@node JIT Compiler
-@section JIT Compiler
-
-Vectorization is the preferred technique for eliminating loops and speeding up
-code.  Nevertheless, it is not always possible to replace every loop.  In such
-situations it may be worth trying Octave's @strong{experimental} Just-In-Time
-(JIT) compiler.
-
-A JIT compiler works by analyzing the body of a loop, translating the Octave
-statements into another language, compiling the new code segment into an
-executable, and then running the executable and collecting any results.  The
-process is not simple and there is a significant amount of work to perform for
-each step.  It can still make sense, however, if the number of loop iterations
-is large.  Because Octave is an interpreted language every time through a
-loop Octave must parse the statements in the loop body before executing them.
-With a JIT compiler this is done just once when the body is translated to
-another language.
-
-The JIT compiler is a very new feature in Octave and not all valid Octave
-statements can currently be accelerated.  However, if no other technique
-is available it may be worth benchmarking the code with JIT enabled.  The
-function @code{jit_enable} is used to turn compilation on or off.  The
-function @code{jit_startcnt} sets the threshold for acceleration.  Loops
-with iteration counts above @code{jit_startcnt} will be accelerated.  The
-functions @code{jit_failcnt} and @code{debug_jit} are not likely to be of use
-to anyone not working directly on the implementation of the JIT compiler.
-
-@DOCSTRING(jit_enable)
-
-@DOCSTRING(jit_startcnt)
-
-@DOCSTRING(jit_failcnt)
-
-@DOCSTRING(debug_jit)
-
 @node Miscellaneous Techniques
 @section Miscellaneous Techniques
 @cindex execution speed
--- a/libinterp/build-env.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/build-env.h	Tue Aug 10 16:42:29 2021 -0400
@@ -121,9 +121,6 @@
     extern OCTINTERP_API const char *MAGICK_CPPFLAGS;
     extern OCTINTERP_API const char *MAGICK_LDFLAGS;
     extern OCTINTERP_API const char *MAGICK_LIBS;
-    extern OCTINTERP_API const char *LLVM_CPPFLAGS;
-    extern OCTINTERP_API const char *LLVM_LDFLAGS;
-    extern OCTINTERP_API const char *LLVM_LIBS;
     extern OCTINTERP_API const char *MKOCTFILE_DL_LDFLAGS;
     extern OCTINTERP_API const char *OCTAVE_LINK_DEPS;
     extern OCTINTERP_API const char *OCTAVE_LINK_OPTS;
--- a/libinterp/build-env.in.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/build-env.in.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -205,12 +205,6 @@
 
     const char *MAGICK_LIBS = %OCTAVE_CONF_MAGICK_LIBS%;
 
-    const char *LLVM_CPPFLAGS = %OCTAVE_CONF_LLVM_CPPFLAGS%;
-
-    const char *LLVM_LDFLAGS = %OCTAVE_CONF_LLVM_LDFLAGS%;
-
-    const char *LLVM_LIBS = %OCTAVE_CONF_LLVM_LIBS%;
-
     const char *MKOCTFILE_DL_LDFLAGS = %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%;
 
     const char *OCTAVE_LINK_DEPS = %OCTAVE_CONF_OCTAVE_LINK_DEPS%;
--- a/libinterp/corefcn/interpreter.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/corefcn/interpreter.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -610,12 +610,6 @@
         if (! info_program.empty ())
           Finfo_program (*this, octave_value (info_program));
 
-        if (options.debug_jit ())
-          Fdebug_jit (octave_value (true));
-
-        if (options.jit_compiler ())
-          Fjit_enable (octave_value (true));
-
         std::string texi_macros_file = options.texi_macros_file ();
         if (! texi_macros_file.empty ())
           Ftexi_macros_file (*this, octave_value (texi_macros_file));
--- a/libinterp/corefcn/module.mk	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/corefcn/module.mk	Tue Aug 10 16:42:29 2021 -0400
@@ -331,7 +331,6 @@
   $(FONTCONFIG_CPPFLAGS) \
   $(FT2_CPPFLAGS) \
   $(HDF5_CPPFLAGS) \
-  $(LLVM_CPPFLAGS) \
   $(SPARSE_XCPPFLAGS) \
   $(Z_CPPFLAGS) \
   $(OCTAVE_TEX_PARSER_CPPFLAGS)
--- a/libinterp/corefcn/toplev.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/corefcn/toplev.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -386,12 +386,6 @@
            { "ENABLE_FLOAT_TRUNCATE", false },
 #endif
 
-#if defined (ENABLE_JIT)
-           { "ENABLE_JIT", true },
-#else
-           { "ENABLE_JIT", false },
-#endif
-
 #if defined (OCTAVE_ENABLE_OPENMP)
            { "ENABLE_OPENMP", true },
 #else
@@ -521,9 +515,6 @@
            { "LIBOCTAVE", octave::build_env::LIBOCTAVE },
            { "LIBOCTINTERP", octave::build_env::LIBOCTINTERP },
            { "LIBS", octave::build_env::LIBS },
-           { "LLVM_CPPFLAGS", octave::build_env::LLVM_CPPFLAGS },
-           { "LLVM_LDFLAGS", octave::build_env::LLVM_LDFLAGS },
-           { "LLVM_LIBS", octave::build_env::LLVM_LIBS },
            { "LN_S", octave::build_env::LN_S },
            { "MAGICK_CPPFLAGS", octave::build_env::MAGICK_CPPFLAGS },
            { "MAGICK_LDFLAGS", octave::build_env::MAGICK_LDFLAGS },
--- a/libinterp/octave-value/ov-base.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave-value/ov-base.h	Tue Aug 10 16:42:29 2021 -0400
@@ -863,21 +863,6 @@
   virtual bool
   fast_elem_insert_self (void *where, builtin_type_t btyp) const;
 
-  // Grab the reference count.  For use by jit.
-  void
-  grab (void)
-  {
-    ++count;
-  }
-
-  // Release the reference count.  For use by jit.
-  void
-  release (void)
-  {
-    if (--count == 0)
-      delete this;
-  }
-
 protected:
 
   // This should only be called for derived types.
--- a/libinterp/octave-value/ov-builtin.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave-value/ov-builtin.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -87,18 +87,6 @@
   return retval;
 }
 
-octave::jit_type *
-octave_builtin::to_jit (void) const
-{
-  return m_jtype;
-}
-
-void
-octave_builtin::stash_jit (octave::jit_type& type)
-{
-  m_jtype = &type;
-}
-
 octave_builtin::fcn
 octave_builtin::function (void) const
 {
--- a/libinterp/octave-value/ov-builtin.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave-value/ov-builtin.h	Tue Aug 10 16:42:29 2021 -0400
@@ -42,7 +42,6 @@
 {
   class tree_evaluator;
   class interpreter;
-  class jit_type;
 }
 
 // Builtin functions.
@@ -54,8 +53,7 @@
 public:
 
   octave_builtin (void)
-    : octave_function (), m_fcn (nullptr), m_meth (nullptr), m_file (),
-      m_jtype (nullptr)
+    : octave_function (), m_fcn (nullptr), m_meth (nullptr), m_file ()
   { }
 
   typedef octave_value_list (*meth) (octave::interpreter&,
@@ -65,26 +63,22 @@
 
   octave_builtin (fcn ff, const std::string& nm = "",
                   const std::string& ds = "")
-    : octave_function (nm, ds), m_fcn (ff), m_meth (nullptr), m_file (),
-      m_jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (ff), m_meth (nullptr), m_file ()
   { }
 
   octave_builtin (meth mm, const std::string& nm = "",
                   const std::string& ds = "")
-    : octave_function (nm, ds), m_fcn (nullptr), m_meth (mm), m_file (),
-      m_jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (nullptr), m_meth (mm), m_file ()
   { }
 
   octave_builtin (fcn ff, const std::string& nm, const std::string& fnm,
                   const std::string& ds)
-    : octave_function (nm, ds), m_fcn (ff), m_meth (nullptr), m_file (fnm),
-      m_jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (ff), m_meth (nullptr), m_file (fnm)
   { }
 
   octave_builtin (meth mm, const std::string& nm, const std::string& fnm,
                   const std::string& ds)
-    : octave_function (nm, ds), m_fcn (nullptr), m_meth (mm), m_file (fnm),
-      m_jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (nullptr), m_meth (mm), m_file (fnm)
   { }
 
   // No copying!
@@ -105,10 +99,6 @@
   execute (octave::tree_evaluator& tw, int nargout = 0,
            const octave_value_list& args = octave_value_list ());
 
-  octave::jit_type * to_jit (void) const;
-
-  void stash_jit (octave::jit_type& type);
-
   fcn function (void) const;
 
   meth method (void) const;
@@ -129,9 +119,6 @@
   // The types this function has been declared to handle (if any).
   std::set<std::string> m_dispatch_classes;
 
-  // A pointer to the jit type that represents the function.
-  octave::jit_type *m_jtype;
-
 private:
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
--- a/libinterp/octave-value/ov-usr-fcn.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -46,7 +46,6 @@
 #include "ov.h"
 #include "pager.h"
 #include "pt-eval.h"
-#include "pt-jit.h"
 #include "pt-jump.h"
 #include "pt-misc.h"
 #include "pt-pr-code.h"
@@ -224,9 +223,6 @@
     m_subfunction (false), m_inline_function (false),
     m_anonymous_function (false), m_nested_function (false),
     m_class_constructor (none), m_class_method (none)
-#if defined (HAVE_LLVM)
-    , m_jit_info (0)
-#endif
 {
   if (cmd_list)
     cmd_list->mark_as_function_body ();
@@ -238,10 +234,6 @@
   delete m_ret_list;
   delete m_lead_comm;
   delete m_trail_comm;
-
-#if defined (HAVE_LLVM)
-  delete m_jit_info;
-#endif
 }
 
 octave_user_function *
--- a/libinterp/octave-value/ov-usr-fcn.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.h	Tue Aug 10 16:42:29 2021 -0400
@@ -52,10 +52,6 @@
   class tree_evaluator;
   class tree_expression;
   class tree_walker;
-#if defined (HAVE_LLVM)
-  class jit_function_info;
-#endif
-
 }
 
 class
@@ -407,12 +403,6 @@
 
   void accept (octave::tree_walker& tw);
 
-#if defined (HAVE_LLVM)
-  octave::jit_function_info * get_info (void) { return m_jit_info; }
-
-  void stash_info (octave::jit_function_info *info) { m_jit_info = info; }
-#endif
-
   octave_value dump (void) const;
 
 private:
@@ -478,10 +468,6 @@
   // Enum describing whether this function is a method for a class.
   class_method_type m_class_method;
 
-#if defined (HAVE_LLVM)
-  octave::jit_function_info *m_jit_info;
-#endif
-
   void maybe_relocate_end_internal (void);
 
   void print_code_function_header (const std::string& prefix);
--- a/libinterp/octave.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -181,14 +181,6 @@
               m_info_program = octave_optarg_wrapper ();
             break;
 
-          case DEBUG_JIT_OPTION:
-            m_debug_jit = true;
-            break;
-
-          case JIT_COMPILER_OPTION:
-            m_jit_compiler = true;
-            break;
-
           case LINE_EDITING_OPTION:
             m_forced_line_editing = m_line_editing = true;
             break;
@@ -251,13 +243,11 @@
 
     m.assign ("sys_argc", sys_argc ());
     m.assign ("sys_argv", string_vector (sys_argv ()));
-    m.assign ("debug_jit", debug_jit ());
     m.assign ("echo_commands", echo_commands ());
     m.assign ("forced_interactive", forced_interactive ());
     m.assign ("forced_line_editing", forced_line_editing ());
     m.assign ("gui", gui ());
     m.assign ("inhibit_startup_message", inhibit_startup_message ());
-    m.assign ("jit_compiler", jit_compiler ());
     m.assign ("line_editing", line_editing ());
     m.assign ("no_window_system", no_window_system ());
     m.assign ("persist", persist ());
--- a/libinterp/octave.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/octave.h	Tue Aug 10 16:42:29 2021 -0400
@@ -55,7 +55,6 @@
     int sys_argc (void) const { return m_all_args.numel (); }
     char **sys_argv (void) const { return m_all_args.c_str_vec (); }
 
-    bool debug_jit (void) const { return m_debug_jit; }
     bool echo_commands (void) const { return m_echo_commands; }
 
     bool experimental_terminal_widget (void) const { return m_experimental_terminal_widget; }
@@ -63,7 +62,6 @@
     bool forced_line_editing (void) const { return m_forced_line_editing; }
     bool gui (void) const { return m_gui; }
     bool inhibit_startup_message (void) const { return m_inhibit_startup_message; }
-    bool jit_compiler (void) const { return m_jit_compiler; }
     bool line_editing (void) const { return m_line_editing; }
 
     bool no_window_system (void) const { return m_no_window_system; }
@@ -87,7 +85,6 @@
     string_vector all_args (void) const { return m_all_args; }
     string_vector remaining_args (void) const { return m_remaining_args; }
 
-    void debug_jit (bool arg) { m_debug_jit = arg; }
     void echo_commands (bool arg) { m_echo_commands = arg; }
 
     void experimental_terminal_widget (bool arg) { m_experimental_terminal_widget = arg; }
@@ -95,7 +92,6 @@
     void forced_interactive (bool arg) { m_forced_interactive = arg; }
     void gui (bool arg) { m_gui = arg; }
     void inhibit_startup_message (bool arg) { m_inhibit_startup_message = arg; }
-    void jit_compiler (bool arg) { m_jit_compiler = arg; }
     void line_editing (bool arg) { m_line_editing = arg; }
 
     void no_window_system (bool arg) { m_no_window_system = arg; }
@@ -123,10 +119,6 @@
 
   private:
 
-    // TRUE means enable debug tracing for the JIT compiler.
-    // (--debug-jit)
-    bool m_debug_jit = false;
-
     // If TRUE, echo commands as they are read and executed.
     // (--echo-commands, -x)
     bool m_echo_commands = false;
@@ -151,10 +143,6 @@
     // (--quiet; --silent; -q)
     bool m_inhibit_startup_message = false;
 
-    // TRUE means enable the JIT compiler.
-    // (--jit-compiler)
-    bool m_jit_compiler = false;
-
     // TRUE means we are using readline.
     // (--no-line-editing)
     bool m_line_editing = true;
--- a/libinterp/options.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/options.h	Tue Aug 10 16:42:29 2021 -0400
@@ -46,25 +46,22 @@
 #define IMAGE_PATH_OPTION 7
 #define INFO_FILE_OPTION 8
 #define INFO_PROG_OPTION 9
-#define DEBUG_JIT_OPTION 10
-#define JIT_COMPILER_OPTION 11
-#define LINE_EDITING_OPTION 12
-#define NO_GUI_OPTION 13
-#define NO_GUI_LIBS_OPTION 14
-#define NO_INIT_FILE_OPTION 15
-#define NO_INIT_PATH_OPTION 16
-#define NO_LINE_EDITING_OPTION 17
-#define NO_SITE_FILE_OPTION 18
-#define PERSIST_OPTION 19
-#define SERVER_OPTION 20
-#define TEXI_MACROS_FILE_OPTION 21
-#define TRADITIONAL_OPTION 22
+#define LINE_EDITING_OPTION 10
+#define NO_GUI_OPTION 11
+#define NO_GUI_LIBS_OPTION 12
+#define NO_INIT_FILE_OPTION 13
+#define NO_INIT_PATH_OPTION 14
+#define NO_LINE_EDITING_OPTION 15
+#define NO_SITE_FILE_OPTION 16
+#define PERSIST_OPTION 17
+#define SERVER_OPTION 18
+#define TEXI_MACROS_FILE_OPTION 19
+#define TRADITIONAL_OPTION 20
 struct octave_getopt_options long_opts[] =
 {
   { "braindead",                octave_no_arg,       nullptr, TRADITIONAL_OPTION },
   { "built-in-docstrings-file", octave_required_arg, nullptr, BUILT_IN_DOCSTRINGS_FILE_OPTION },
   { "debug",                    octave_no_arg,       nullptr, 'd' },
-  { "debug-jit",                octave_no_arg,       nullptr, DEBUG_JIT_OPTION },
   { "doc-cache-file",           octave_required_arg, nullptr, DOC_CACHE_FILE_OPTION },
   { "echo-commands",            octave_no_arg,       nullptr, 'x' },
   { "eval",                     octave_required_arg, nullptr, EVAL_OPTION },
@@ -77,7 +74,6 @@
   { "info-file",                octave_required_arg, nullptr, INFO_FILE_OPTION },
   { "info-program",             octave_required_arg, nullptr, INFO_PROG_OPTION },
   { "interactive",              octave_no_arg,       nullptr, 'i' },
-  { "jit-compiler",             octave_no_arg,       nullptr, JIT_COMPILER_OPTION },
   { "line-editing",             octave_no_arg,       nullptr, LINE_EDITING_OPTION },
   { "no-gui",                   octave_no_arg,       nullptr, NO_GUI_OPTION },
   { "no-gui-libs",              octave_no_arg,       nullptr, NO_GUI_LIBS_OPTION },
--- a/libinterp/parse-tree/jit-ir.cc	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,849 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-// defines required by llvm
-#define __STDC_LIMIT_MACROS
-#define __STDC_CONSTANT_MACROS
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined (HAVE_LLVM)
-
-#include "jit-ir.h"
-
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-#  include <llvm/IR/BasicBlock.h>
-#  include <llvm/IR/Instructions.h>
-#else
-#  include <llvm/BasicBlock.h>
-#  include <llvm/Instructions.h>
-#endif
-
-#include "error.h"
-
-namespace octave
-{
-
-  // -------------------- jit_factory --------------------
-  jit_factory::~jit_factory (void)
-  {
-    for (auto iter = m_all_values.begin ();
-         iter != m_all_values.end (); ++iter)
-      delete *iter;
-  }
-
-  void
-  jit_factory::track_value (jit_value *value)
-  {
-    if (value->type ())
-      m_constants.push_back (value);
-    m_all_values.push_back (value);
-  }
-
-  // -------------------- jit_block_list --------------------
-  void
-  jit_block_list::insert_after (iterator iter, jit_block *ablock)
-  {
-    ++iter;
-    insert_before (iter, ablock);
-  }
-
-  void
-  jit_block_list::insert_after (jit_block *loc, jit_block *ablock)
-  {
-    insert_after (loc->location (), ablock);
-  }
-
-  void
-  jit_block_list::insert_before (iterator iter, jit_block *ablock)
-  {
-    iter = m_list.insert (iter, ablock);
-    ablock->stash_location (iter);
-  }
-
-  void
-  jit_block_list::insert_before (jit_block *loc, jit_block *ablock)
-  {
-    insert_before (loc->location (), ablock);
-  }
-
-  void
-  jit_block_list::label (void)
-  {
-    if (m_list.size ())
-      {
-        jit_block *block = m_list.back ();
-        block->label ();
-      }
-  }
-
-  std::ostream&
-  jit_block_list::print (std::ostream& os, const std::string& header) const
-  {
-    os << "-------------------- " << header << " --------------------\n";
-    return os << *this;
-  }
-
-  std::ostream&
-  jit_block_list::print_dom (std::ostream& os) const
-  {
-    os << "-------------------- dom info --------------------\n";
-    for (auto iter = begin (); iter != end (); ++iter)
-      {
-        assert (*iter);
-        (*iter)->print_dom (os);
-      }
-    os << std::endl;
-
-    return os;
-  }
-
-  void
-  jit_block_list::push_back (jit_block *b)
-  {
-    m_list.push_back (b);
-    auto iter = m_list.end ();
-    b->stash_location (--iter);
-  }
-
-  std::ostream&
-  operator<<(std::ostream& os, const jit_block_list& blocks)
-  {
-    for (auto iter = blocks.begin (); iter != blocks.end (); ++iter)
-      {
-        assert (*iter);
-        (*iter)->print (os, 0);
-      }
-    return os << std::endl;
-  }
-
-  // -------------------- jit_use --------------------
-  jit_block *
-  jit_use::user_parent (void) const
-  {
-    return m_user->parent ();
-  }
-
-  // -------------------- jit_value --------------------
-  jit_value::~jit_value (void)
-  { }
-
-  jit_block *
-  jit_value::first_use_block (void)
-  {
-    jit_use *use = first_use ();
-    while (use)
-      {
-        if (! isa<jit_error_check> (use->user ()))
-          return use->user_parent ();
-
-        use = use->next ();
-      }
-
-    return 0;
-  }
-
-  void
-  jit_value::replace_with (jit_value *value)
-  {
-    while (first_use ())
-      {
-        jit_instruction *user = first_use ()->user ();
-        std::size_t idx = first_use ()->index ();
-        user->stash_argument (idx, value);
-      }
-  }
-
-#define JIT_METH(clname)                                \
-  void                                                  \
-  jit_ ## clname::accept (jit_ir_walker& walker)        \
-  {                                                     \
-    walker.visit (*this);                               \
-  }
-
-  JIT_VISIT_IR_NOTEMPLATE
-#undef JIT_METH
-
-  std::ostream&
-  operator<< (std::ostream& os, const jit_value& value)
-  {
-    return value.short_print (os);
-  }
-
-  std::ostream&
-  jit_print (std::ostream& os, jit_value *avalue)
-  {
-    if (avalue)
-      return avalue->print (os);
-    return os << "NULL";
-  }
-
-  // -------------------- jit_instruction --------------------
-  void
-  jit_instruction::remove (void)
-  {
-    if (m_parent)
-      m_parent->remove (m_location);
-    resize_arguments (0);
-  }
-
-  llvm::BasicBlock *
-  jit_instruction::parent_llvm (void) const
-  {
-    return m_parent->to_llvm ();
-  }
-
-  std::ostream&
-  jit_instruction::short_print (std::ostream& os) const
-  {
-    if (type ())
-      jit_print (os, type ()) << ": ";
-    return os << '#' << m_id;
-  }
-
-  void
-  jit_instruction::do_construct_ssa (std::size_t start, std::size_t end)
-  {
-    for (std::size_t i = start; i < end; ++i)
-      {
-        jit_value *arg = argument (i);
-        jit_variable *var = dynamic_cast<jit_variable *> (arg);
-        if (var && var->has_top ())
-          stash_argument (i, var->top ());
-      }
-  }
-
-  // -------------------- jit_block --------------------
-  void
-  jit_block::replace_with (jit_value *value)
-  {
-    assert (isa<jit_block> (value));
-    jit_block *block = static_cast<jit_block *> (value);
-
-    jit_value::replace_with (block);
-
-    while (ILIST_T::first_use ())
-      {
-        jit_phi_incoming *incoming = ILIST_T::first_use ();
-        incoming->stash_value (block);
-      }
-  }
-
-  void
-  jit_block::replace_in_phi (jit_block *ablock, jit_block *with)
-  {
-    jit_phi_incoming *node = ILIST_T::first_use ();
-    while (node)
-      {
-        jit_phi_incoming *prev = node;
-        node = node->next ();
-
-        if (prev->user_parent () == ablock)
-          prev->stash_value (with);
-      }
-  }
-
-  jit_block *
-  jit_block::maybe_merge (void)
-  {
-    if (successor_count () == 1 && successor (0) != this
-        && (successor (0)->use_count () == 1 || m_instructions.size () == 1))
-      {
-        jit_block *to_merge = successor (0);
-        merge (*to_merge);
-        return to_merge;
-      }
-
-    return 0;
-  }
-
-  void
-  jit_block::merge (jit_block& block)
-  {
-    // the merge block will contain a new terminator
-    jit_terminator *old_term = terminator ();
-    if (old_term)
-      old_term->remove ();
-
-    bool was_empty = end () == begin ();
-    auto merge_begin = end ();
-    if (! was_empty)
-      --merge_begin;
-
-    m_instructions.splice (end (), block.m_instructions);
-    if (was_empty)
-      merge_begin = begin ();
-    else
-      ++merge_begin;
-
-    // now merge_begin points to the start of the new instructions, we must
-    // update their parent information
-    for (auto iter = merge_begin; iter != end (); ++iter)
-      {
-        jit_instruction *instr = *iter;
-        instr->stash_parent (this, iter);
-      }
-
-    block.replace_with (this);
-  }
-
-  jit_instruction *
-  jit_block::prepend (jit_instruction *instr)
-  {
-    m_instructions.push_front (instr);
-    instr->stash_parent (this, m_instructions.begin ());
-    return instr;
-  }
-
-  jit_instruction *
-  jit_block::prepend_after_phi (jit_instruction *instr)
-  {
-    // FIXME: Make this O(1)
-    for (auto iter = begin (); iter != end (); ++iter)
-      {
-        jit_instruction *temp = *iter;
-        if (! isa<jit_phi> (temp))
-          {
-            insert_before (iter, instr);
-            return instr;
-          }
-      }
-
-    return append (instr);
-  }
-
-  void
-  jit_block::internal_append (jit_instruction *instr)
-  {
-    m_instructions.push_back (instr);
-    instr->stash_parent (this, --m_instructions.end ());
-  }
-
-  jit_instruction *
-  jit_block::insert_before (iterator loc, jit_instruction *instr)
-  {
-    auto iloc = m_instructions.insert (loc, instr);
-    instr->stash_parent (this, iloc);
-    return instr;
-  }
-
-  jit_instruction *
-  jit_block::insert_after (iterator loc, jit_instruction *instr)
-  {
-    ++loc;
-    auto iloc = m_instructions.insert (loc, instr);
-    instr->stash_parent (this, iloc);
-    return instr;
-  }
-
-  jit_terminator *
-  jit_block::terminator (void) const
-  {
-    if (m_instructions.empty ())
-      return nullptr;
-
-    jit_instruction *last = m_instructions.back ();
-    return dynamic_cast<jit_terminator *> (last);
-  }
-
-  bool
-  jit_block::branch_alive (jit_block *asucc) const
-  {
-    return terminator ()->alive (asucc);
-  }
-
-  jit_block *
-  jit_block::successor (std::size_t i) const
-  {
-    jit_terminator *term = terminator ();
-    return term->successor (i);
-  }
-
-  std::size_t
-  jit_block::successor_count (void) const
-  {
-    jit_terminator *term = terminator ();
-    return term ? term->successor_count () : 0;
-  }
-
-  llvm::BasicBlock *
-  jit_block::to_llvm (void) const
-  {
-    return llvm::cast<llvm::BasicBlock> (m_llvm_value);
-  }
-
-  std::ostream&
-  jit_block::print_dom (std::ostream& os) const
-  {
-    short_print (os);
-    os << ":\n";
-    os << "  m_id: " << m_id << std::endl;
-    os << "  predecessors: ";
-    for (jit_use *use = first_use (); use; use = use->next ())
-      os << *use->user_parent () << ' ';
-    os << std::endl;
-
-    os << "  successors: ";
-    for (std::size_t i = 0; i < successor_count (); ++i)
-      os << *successor (i) << ' ';
-    os << std::endl;
-
-    os << "  m_idom: ";
-    if (m_idom)
-      os << *m_idom;
-    else
-      os << "NULL";
-    os << std::endl;
-    os << "  df: ";
-    for (auto iter = df_begin (); iter != df_end (); ++iter)
-      os << **iter << ' ';
-    os << std::endl;
-
-    os << "  m_dom_succ: ";
-    for (std::size_t i = 0; i < m_dom_succ.size (); ++i)
-      os << *m_dom_succ[i] << ' ';
-
-    return os << std::endl;
-  }
-
-  void
-  jit_block::compute_df (std::size_t avisit_count)
-  {
-    if (visited (avisit_count))
-      return;
-
-    if (use_count () >= 2)
-      {
-        for (jit_use *use = first_use (); use; use = use->next ())
-          {
-            jit_block *runner = use->user_parent ();
-            while (runner != m_idom)
-              {
-                runner->m_df.insert (this);
-                runner = runner->m_idom;
-              }
-          }
-      }
-
-    for (std::size_t i = 0; i < successor_count (); ++i)
-      successor (i)->compute_df (avisit_count);
-  }
-
-  bool
-  jit_block::update_idom (std::size_t avisit_count)
-  {
-    if (visited (avisit_count) || ! use_count ())
-      return false;
-
-    bool changed = false;
-    for (jit_use *use = first_use (); use; use = use->next ())
-      {
-        jit_block *pred = use->user_parent ();
-        changed = pred->update_idom (avisit_count) || changed;
-      }
-
-    jit_use *use = first_use ();
-    jit_block *new_idom = use->user_parent ();
-    use = use->next ();
-
-    for (; use; use = use->next ())
-      {
-        jit_block *pred = use->user_parent ();
-        jit_block *pidom = pred->m_idom;
-        if (pidom)
-          new_idom = idom_intersect (pidom, new_idom);
-      }
-
-    if (m_idom != new_idom)
-      {
-        m_idom = new_idom;
-        return true;
-      }
-
-    return changed;
-  }
-
-  void
-  jit_block::label (std::size_t avisit_count, std::size_t& number)
-  {
-    if (visited (avisit_count))
-      return;
-
-    for (jit_use *use = first_use (); use; use = use->next ())
-      {
-        jit_block *pred = use->user_parent ();
-        pred->label (avisit_count, number);
-      }
-
-    m_id = number++;
-  }
-
-  void
-  jit_block::pop_all (void)
-  {
-    for (auto iter = begin (); iter != end (); ++iter)
-      {
-        jit_instruction *instr = *iter;
-        instr->pop_variable ();
-      }
-  }
-
-  std::ostream&
-  jit_block::print (std::ostream& os, std::size_t indent) const
-  {
-    print_indent (os, indent);
-    short_print (os) << ":        %pred = ";
-    for (jit_use *use = first_use (); use; use = use->next ())
-      {
-        jit_block *pred = use->user_parent ();
-        os << *pred;
-        if (use->next ())
-          os << ", ";
-      }
-    os << std::endl;
-
-    for (auto iter = begin (); iter != end (); ++iter)
-      {
-        jit_instruction *instr = *iter;
-        instr->print (os, indent + 1) << std::endl;
-      }
-    return os;
-  }
-
-  jit_block *
-  jit_block::maybe_split (jit_factory& factory, jit_block_list& blocks,
-                          jit_block *asuccessor)
-  {
-    if (successor_count () > 1)
-      {
-        jit_terminator *term = terminator ();
-        std::size_t idx = term->successor_index (asuccessor);
-        jit_block *split = factory.create<jit_block> ("phi_split", m_visit_count);
-
-        // place after this to ensure define before use in the blocks list
-        blocks.insert_after (this, split);
-
-        term->stash_argument (idx, split);
-        jit_branch *br = split->append (factory.create<jit_branch> (asuccessor));
-        replace_in_phi (asuccessor, split);
-
-        if (alive ())
-          {
-            split->mark_alive ();
-            br->infer ();
-          }
-
-        return split;
-      }
-
-    return this;
-  }
-
-  void
-  jit_block::create_dom_tree (std::size_t avisit_count)
-  {
-    if (visited (avisit_count))
-      return;
-
-    if (m_idom != this)
-      m_idom->m_dom_succ.push_back (this);
-
-    for (std::size_t i = 0; i < successor_count (); ++i)
-      successor (i)->create_dom_tree (avisit_count);
-  }
-
-  jit_block *
-  jit_block::idom_intersect (jit_block *i, jit_block *j)
-  {
-    while (i && j && i != j)
-      {
-        while (i && i->id () > j->id ())
-          i = i->m_idom;
-
-        while (i && j && j->id () > i->id ())
-          j = j->m_idom;
-      }
-
-    return i ? i : j;
-  }
-
-  // -------------------- jit_phi_incoming --------------------
-
-  jit_block *
-  jit_phi_incoming::user_parent (void) const
-  { return m_user->parent (); }
-
-  // -------------------- jit_phi --------------------
-  bool
-  jit_phi::prune (void)
-  {
-    jit_block *p = parent ();
-    std::size_t new_idx = 0;
-    jit_value *unique = argument (1);
-
-    for (std::size_t i = 0; i < argument_count (); ++i)
-      {
-        jit_block *inc = incoming (i);
-        if (inc->branch_alive (p))
-          {
-            if (unique != argument (i))
-              unique = 0;
-
-            if (new_idx != i)
-              {
-                stash_argument (new_idx, argument (i));
-                m_incoming[new_idx].stash_value (inc);
-              }
-
-            ++new_idx;
-          }
-      }
-
-    if (new_idx != argument_count ())
-      {
-        resize_arguments (new_idx);
-        m_incoming.resize (new_idx);
-      }
-
-    assert (argument_count () > 0);
-    if (unique)
-      {
-        replace_with (unique);
-        return true;
-      }
-
-    return false;
-  }
-
-  bool
-  jit_phi::infer (void)
-  {
-    jit_block *p = parent ();
-    if (! p->alive ())
-      return false;
-
-    jit_type *infered = nullptr;
-    for (std::size_t i = 0; i < argument_count (); ++i)
-      {
-        jit_block *inc = incoming (i);
-        if (inc->branch_alive (p))
-          infered = jit_type_join (infered, argument_type (i));
-      }
-
-    if (infered != type ())
-      {
-        stash_type (infered);
-        return true;
-      }
-
-    return false;
-  }
-
-  llvm::PHINode *
-  jit_phi::to_llvm (void) const
-  {
-    return llvm::cast<llvm::PHINode> (jit_value::to_llvm ());
-  }
-
-  // -------------------- jit_terminator --------------------
-  std::size_t
-  jit_terminator::successor_index (const jit_block *asuccessor) const
-  {
-    std::size_t scount = successor_count ();
-    for (std::size_t i = 0; i < scount; ++i)
-      if (successor (i) == asuccessor)
-        return i;
-
-    panic_impossible ();
-  }
-
-  bool
-  jit_terminator::infer (void)
-  {
-    if (! parent ()->alive ())
-      return false;
-
-    bool changed = false;
-    for (std::size_t i = 0; i < m_alive.size (); ++i)
-      if (! m_alive[i] && check_alive (i))
-        {
-          changed = true;
-          m_alive[i] = true;
-          successor (i)->mark_alive ();
-        }
-
-    return changed;
-  }
-
-  llvm::TerminatorInst *
-  jit_terminator::to_llvm (void) const
-  {
-    return llvm::cast<llvm::TerminatorInst> (jit_value::to_llvm ());
-  }
-
-  // -------------------- jit_call --------------------
-  bool
-  jit_call::needs_release (void) const
-  {
-    if (type () && jit_typeinfo::get_release (type ()).valid ())
-      {
-        for (jit_use *use = first_use (); use; use = use->next ())
-          {
-            jit_assign *assign = dynamic_cast<jit_assign *> (use->user ());
-            if (assign && assign->artificial ())
-              return false;
-          }
-
-        return true;
-      }
-    return false;
-  }
-
-  bool
-  jit_call::infer (void)
-  {
-    // FIXME: explain algorithm
-    for (std::size_t i = 0; i < argument_count (); ++i)
-      {
-        m_already_infered[i] = argument_type (i);
-        if (! m_already_infered[i])
-          return false;
-      }
-
-    jit_type *infered = m_operation.result (m_already_infered);
-    if (! infered && use_count ())
-      {
-        std::stringstream ss;
-        ss << "Missing overload in type inference for ";
-        print (ss, 0);
-        throw jit_fail_exception (ss.str ());
-      }
-
-    if (infered != type ())
-      {
-        stash_type (infered);
-        return true;
-      }
-
-    return false;
-  }
-
-  // -------------------- jit_error_check --------------------
-  std::string
-  jit_error_check::variable_to_string (variable v)
-  {
-    switch (v)
-      {
-      case var_error_state:
-        return "error_state";
-      case var_interrupt:
-        return "interrupt";
-      default:
-        panic_impossible ();
-      }
-  }
-
-  std::ostream&
-  jit_error_check::print (std::ostream& os, std::size_t indent) const
-  {
-    print_indent (os, indent) << "error_check " << variable_to_string (m_variable)
-                              << ", ";
-
-    if (has_check_for ())
-      os << "<for> " << *check_for () << ", ";
-    print_successor (os << "<normal> ", 1) << ", ";
-    return print_successor (os << "<error> ", 0);
-  }
-
-  // -------------------- jit_magic_end --------------------
-  jit_magic_end::context::context (jit_factory& factory, jit_value *avalue,
-                                   std::size_t aindex, std::size_t acount)
-    : m_value (avalue), m_index (factory.create<jit_const_index> (aindex)),
-      m_count (factory.create<jit_const_index> (acount))
-  { }
-
-  jit_magic_end::jit_magic_end (const std::vector<context>& full_context)
-    : m_contexts (full_context)
-  {
-    resize_arguments (m_contexts.size ());
-
-    std::size_t i;
-    std::vector<context>::const_iterator iter;
-    for (iter = m_contexts.begin (), i = 0; iter != m_contexts.end (); ++iter, ++i)
-      stash_argument (i, iter->m_value);
-  }
-
-  jit_magic_end::context
-  jit_magic_end::resolve_context (void) const
-  {
-    std::size_t idx;
-    for (idx = 0; idx < m_contexts.size (); ++idx)
-      {
-        jit_type *ctx_type = m_contexts[idx].m_value->type ();
-        if (! ctx_type || ctx_type->skip_paren ())
-          break;
-      }
-
-    if (idx >= m_contexts.size ())
-      idx = 0;
-
-    context ret = m_contexts[idx];
-    ret.m_value = argument (idx);
-    return ret;
-  }
-
-  bool
-  jit_magic_end::infer (void)
-  {
-    jit_type *new_type = overload ().result ();
-    if (new_type != type ())
-      {
-        stash_type (new_type);
-        return true;
-      }
-
-    return false;
-  }
-
-  std::ostream&
-  jit_magic_end::print (std::ostream& os, std::size_t indent) const
-  {
-    context ctx = resolve_context ();
-    short_print (print_indent (os, indent)) << " (" << *ctx.m_value << ", ";
-    return os << *ctx.m_index << ", " << *ctx.m_count << ')';
-  }
-
-  const jit_function&
-  jit_magic_end::overload (void) const
-  {
-    const context& ctx = resolve_context ();
-    return jit_typeinfo::end (ctx.m_value, ctx.m_index, ctx.m_count);
-  }
-
-}
-
-#endif
--- a/libinterp/parse-tree/jit-ir.h	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1489 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-#if ! defined (octave_jit_ir_h)
-#define octave_jit_ir_h 1
-
-#include "octave-config.h"
-
-#if defined (HAVE_LLVM)
-
-#include <list>
-#include <stack>
-#include <set>
-
-#include "jit-typeinfo.h"
-
-namespace octave
-{
-
-  // The low level octave JIT IR.  This ir is close to llvm, but
-  // contains information for doing type inference.  We convert the
-  // octave parse tree to this IR directly.
-
-#define JIT_VISIT_IR_NOTEMPLATE                 \
-  JIT_METH (block);                             \
-  JIT_METH (branch);                            \
-  JIT_METH (cond_branch);                       \
-  JIT_METH (call);                              \
-  JIT_METH (extract_argument);                  \
-  JIT_METH (store_argument);                    \
-  JIT_METH (return);                            \
-  JIT_METH (phi);                               \
-  JIT_METH (variable);                          \
-  JIT_METH (error_check);                       \
-  JIT_METH (assign)                             \
-  JIT_METH (argument)                           \
-  JIT_METH (magic_end)
-
-#define JIT_VISIT_IR_CONST                      \
-  JIT_METH (const_bool);                        \
-  JIT_METH (const_scalar);                      \
-  JIT_METH (const_complex);                     \
-  JIT_METH (const_index);                       \
-  JIT_METH (const_string);                      \
-  JIT_METH (const_range)
-
-#define JIT_VISIT_IR_CLASSES                    \
-  JIT_VISIT_IR_NOTEMPLATE                       \
-  JIT_VISIT_IR_CONST
-
-  // forward declare all ir classes
-#define JIT_METH(cname)                         \
-  class jit_ ## cname;
-
-  JIT_VISIT_IR_NOTEMPLATE
-
-#undef JIT_METH
-
-  // ABCs which aren't included in JIT_VISIT_IR_ALL
-  class jit_instruction;
-  class jit_terminator;
-
-  template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T = T,
-            bool QUOTE=false>
-  class jit_const;
-
-  typedef jit_const<bool, jit_typeinfo::get_bool> jit_const_bool;
-  typedef jit_const<double, jit_typeinfo::get_scalar> jit_const_scalar;
-  typedef jit_const<Complex, jit_typeinfo::get_complex> jit_const_complex;
-  typedef jit_const<octave_idx_type, jit_typeinfo::get_index> jit_const_index;
-
-  typedef jit_const<std::string, jit_typeinfo::get_string,
-                    const std::string&, true>
-    jit_const_string;
-  typedef jit_const<jit_range, jit_typeinfo::get_range, const jit_range&>
-    jit_const_range;
-
-  class jit_ir_walker;
-  class jit_use;
-
-  // Creates and tracks memory for jit_value and subclasses.
-  // Memory management is simple, all values that are created live as
-  // long as the factory.
-  class
-  jit_factory
-  {
-    typedef std::list<jit_value *> value_list;
-
-  public:
-
-    ~jit_factory (void);
-
-    const value_list& constants (void) const { return m_constants; }
-
-    template <typename T, typename ...Args>
-    T * create (const Args&... args)
-    {
-      T *ret = new T (args...);
-      track_value (ret);
-      return ret;
-    }
-
-  private:
-
-    void track_value (jit_value *v);
-
-    value_list m_all_values;
-
-    value_list m_constants;
-  };
-
-  // A list of basic blocks (jit_block) which form some body of code.
-  //
-  // We do not directly inherit from std::list because we need to update the
-  // blocks stashed location in push_back and insert.
-  class
-  jit_block_list
-  {
-  public:
-
-    typedef std::list<jit_block *>::iterator iterator;
-    typedef std::list<jit_block *>::const_iterator const_iterator;
-
-    jit_block * back (void) const { return m_list.back (); }
-
-    iterator begin (void) { return m_list.begin (); }
-
-    const_iterator begin (void) const { return m_list.begin (); }
-
-    iterator end (void)  { return m_list.end (); }
-
-    const_iterator end (void) const  { return m_list.end (); }
-
-    iterator erase (iterator iter) { return m_list.erase (iter); }
-
-    jit_block * front (void) const { return m_list.front (); }
-
-    void insert_after (iterator iter, jit_block *ablock);
-
-    void insert_after (jit_block *loc, jit_block *ablock);
-
-    void insert_before (iterator iter, jit_block *ablock);
-
-    void insert_before (jit_block *loc, jit_block *ablock);
-
-    void label (void);
-
-    std::ostream& print (std::ostream& os, const std::string& header) const;
-
-    std::ostream& print_dom (std::ostream& os) const;
-
-    void push_back (jit_block *b);
-
-  private:
-
-    std::list<jit_block *> m_list;
-  };
-
-  std::ostream& operator<<(std::ostream& os, const jit_block_list& blocks);
-
-  class
-  jit_value : public jit_internal_list<jit_value, jit_use>
-  {
-  public:
-
-    jit_value (void)
-      : m_llvm_value (0), m_type (0), m_last_use (0), m_in_worklist (false)
-    { }
-
-    virtual ~jit_value (void);
-
-    bool in_worklist (void) const
-    {
-      return m_in_worklist;
-    }
-
-    void stash_in_worklist (bool ain_worklist)
-    {
-      m_in_worklist = ain_worklist;
-    }
-
-    // The block of the first use which is not a jit_error_check
-    // So this is not necessarily first_use ()->parent ().
-    jit_block * first_use_block (void);
-
-    // replace all uses with
-    virtual void replace_with (jit_value *m_value);
-
-    jit_type * type (void) const { return m_type; }
-
-    llvm::Type * type_llvm (void) const
-    {
-      return m_type ? m_type->to_llvm () : nullptr;
-    }
-
-    const std::string& type_name (void) const
-    {
-      return m_type->name ();
-    }
-
-    void stash_type (jit_type *new_type) { m_type = new_type; }
-
-    std::string print_string (void)
-    {
-      std::stringstream ss;
-      print (ss);
-      return ss.str ();
-    }
-
-    jit_instruction * last_use (void) const { return m_last_use; }
-
-    void stash_last_use (jit_instruction *alast_use)
-    {
-      m_last_use = alast_use;
-    }
-
-    virtual bool needs_release (void) const { return false; }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const = 0;
-
-    virtual std::ostream& short_print (std::ostream& os) const
-    { return print (os); }
-
-    virtual void accept (jit_ir_walker& walker) = 0;
-
-    bool has_llvm (void) const
-    {
-      return m_llvm_value;
-    }
-
-    llvm::Value * to_llvm (void) const
-    {
-      assert (m_llvm_value);
-      return m_llvm_value;
-    }
-
-    void stash_llvm (llvm::Value *compiled)
-    {
-      m_llvm_value = compiled;
-    }
-
-  protected:
-
-    std::ostream& print_indent (std::ostream& os, std::size_t indent = 0) const
-    {
-      for (std::size_t i = 0; i < indent * 8; ++i)
-        os << ' ';
-      return os;
-    }
-
-    llvm::Value *m_llvm_value;
-
-  private:
-
-    jit_type *m_type;
-    jit_instruction *m_last_use;
-    bool m_in_worklist;
-  };
-
-  std::ostream& operator<< (std::ostream& os, const jit_value& value);
-  std::ostream& jit_print (std::ostream& os, jit_value *avalue);
-
-  class
-  jit_use : public jit_internal_node<jit_value, jit_use>
-  {
-  public:
-
-    // some compilers don't allow us to use jit_internal_node without template
-    // parameters
-    typedef jit_internal_node<jit_value, jit_use> PARENT_T;
-
-    jit_use (void) : m_user (0), m_index (0) { }
-
-    // we should really have a move operator, but not until c++11 :(
-    jit_use (const jit_use& use) : m_user (0), m_index (0)
-    {
-      *this = use;
-    }
-
-    jit_use& operator= (const jit_use& use)
-    {
-      stash_value (use.value (), use.user (), use.index ());
-      return *this;
-    }
-
-    std::size_t index (void) const { return m_index; }
-
-    jit_instruction * user (void) const { return m_user; }
-
-    jit_block * user_parent (void) const;
-
-    std::list<jit_block *> user_parent_location (void) const;
-
-    void stash_value (jit_value *avalue, jit_instruction *auser = nullptr,
-                      std::size_t aindex = -1)
-    {
-      PARENT_T::stash_value (avalue);
-      m_index = aindex;
-      m_user = auser;
-    }
-
-  private:
-
-    jit_instruction *m_user;
-    std::size_t m_index;
-  };
-
-  class
-  jit_instruction : public jit_value
-  {
-  public:
-
-    // FIXME: this code could be so much pretier with varadic templates...
-    jit_instruction (void)
-      : m_id (next_id ()), m_parent (0)
-    { }
-
-    jit_instruction (std::size_t nargs)
-      : m_id (next_id ()), m_parent (0)
-    {
-      m_already_infered.reserve (nargs);
-      m_arguments.reserve (nargs);
-    }
-
-    template <typename ...Args>
-    jit_instruction (jit_value * arg1, Args... other_args)
-      : m_already_infered (1 + sizeof... (other_args)),
-        m_arguments (1 + sizeof... (other_args)),
-        m_id (next_id ()), m_parent (nullptr)
-    {
-      stash_argument (0, arg1, other_args...);
-    }
-
-    jit_instruction (const std::vector<jit_value *>& aarguments)
-      : m_already_infered (aarguments.size ()), m_arguments (aarguments.size ()),
-        m_id (next_id ()), m_parent (0)
-    {
-      for (std::size_t i = 0; i < aarguments.size (); ++i)
-        stash_argument (i, aarguments[i]);
-    }
-
-    static void reset_ids (void)
-    {
-      next_id (true);
-    }
-
-    jit_value * argument (std::size_t i) const
-    {
-      return m_arguments[i].value ();
-    }
-
-    llvm::Value * argument_llvm (std::size_t i) const
-    {
-      assert (argument (i));
-      return argument (i)->to_llvm ();
-    }
-
-    jit_type * argument_type (std::size_t i) const
-    {
-      return argument (i)->type ();
-    }
-
-    llvm::Type * argument_type_llvm (std::size_t i) const
-    {
-      assert (argument (i));
-      return argument_type (i)->to_llvm ();
-    }
-
-    std::ostream& print_argument (std::ostream& os, std::size_t i) const
-    {
-      if (argument (i))
-        return argument (i)->short_print (os);
-      else
-        return os << "NULL";
-    }
-
-    void stash_argument (std::size_t i, jit_value * arg)
-    {
-      m_arguments[i].stash_value (arg, this, i);
-    }
-
-    template <typename ...Args>
-    void stash_argument (std::size_t i, jit_value * arg1, Args... aargs)
-    {
-      m_arguments[i].stash_value (arg1, this, i);
-      stash_argument (++i, aargs...);
-    }
-
-    void push_argument (jit_value *arg)
-    {
-      m_arguments.push_back (jit_use ());
-      stash_argument (m_arguments.size () - 1, arg);
-      m_already_infered.push_back (0);
-    }
-
-    std::size_t argument_count (void) const
-    {
-      return m_arguments.size ();
-    }
-
-    void resize_arguments (std::size_t acount, jit_value *adefault = nullptr)
-    {
-      std::size_t old = m_arguments.size ();
-      m_arguments.resize (acount);
-      m_already_infered.resize (acount);
-
-      if (adefault)
-        for (std::size_t i = old; i < acount; ++i)
-          stash_argument (i, adefault);
-    }
-
-    const std::vector<jit_use>& arguments (void) const { return m_arguments; }
-
-    // argument types which have been infered already
-    const std::vector<jit_type *>& argument_types (void) const
-    { return m_already_infered; }
-
-    virtual void push_variable (void) { }
-
-    virtual void pop_variable (void) { }
-
-    virtual void construct_ssa (void)
-    {
-      do_construct_ssa (0, argument_count ());
-    }
-
-    virtual bool infer (void) { return false; }
-
-    void remove (void);
-
-    virtual std::ostream& short_print (std::ostream& os) const;
-
-    jit_block * parent (void) const { return m_parent; }
-
-    std::list<jit_instruction *>::iterator location (void) const
-    {
-      return m_location;
-    }
-
-    llvm::BasicBlock * parent_llvm (void) const;
-
-    void stash_parent (jit_block *aparent,
-                       std::list<jit_instruction *>::iterator alocation)
-    {
-      m_parent = aparent;
-      m_location = alocation;
-    }
-
-    std::size_t id (void) const { return m_id; }
-
-  protected:
-
-    // Do SSA replacement on arguments in [start, end)
-    void do_construct_ssa (std::size_t start, std::size_t end);
-
-    std::vector<jit_type *> m_already_infered;
-
-  private:
-
-    static std::size_t next_id (bool reset = false)
-    {
-      static std::size_t ret = 0;
-      if (reset)
-        return ret = 0;
-
-      return ret++;
-    }
-
-    std::vector<jit_use> m_arguments;
-
-    std::size_t m_id;
-    jit_block *m_parent;
-    std::list<jit_instruction *>::iterator m_location;
-  };
-
-  // defnie accept methods for subclasses
-#define JIT_VALUE_ACCEPT                        \
-  virtual void accept (jit_ir_walker& walker);
-
-  // for use as a dummy argument during conversion to LLVM
-  class
-  jit_argument : public jit_value
-  {
-  public:
-
-    jit_argument (jit_type *atype, llvm::Value *avalue)
-    {
-      stash_type (atype);
-      stash_llvm (avalue);
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent);
-      return jit_print (os, type ()) << ": DUMMY";
-    }
-
-    JIT_VALUE_ACCEPT;
-  };
-
-  template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T, bool QUOTE>
-  class
-  jit_const : public jit_value
-  {
-  public:
-
-    typedef PASS_T pass_t;
-
-    jit_const (PASS_T avalue) : m_value (avalue)
-    {
-      stash_type (EXTRACT_T ());
-    }
-
-    PASS_T value (void) const { return m_value; }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent);
-      jit_print (os, type ()) << ": ";
-      if (QUOTE)
-        os << '"';
-      os << m_value;
-      if (QUOTE)
-        os << '"';
-      return os;
-    }
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    T m_value;
-  };
-
-  class jit_phi_incoming;
-
-  class
-  jit_block : public jit_value, public jit_internal_list<jit_block,
-                                                         jit_phi_incoming>
-  {
-    typedef jit_internal_list<jit_block, jit_phi_incoming> ILIST_T;
-
-  public:
-
-    typedef std::list<jit_instruction *> instruction_list;
-    typedef instruction_list::iterator iterator;
-    typedef instruction_list::const_iterator const_iterator;
-
-    typedef std::set<jit_block *> df_set;
-    typedef df_set::const_iterator df_iterator;
-
-    static const std::size_t NO_ID = static_cast<std::size_t> (-1);
-
-    jit_block (const std::string& aname, std::size_t avisit_count = 0)
-      : m_visit_count (avisit_count), m_id (NO_ID), m_idom (0), m_name (aname),
-        m_alive (false)
-    { }
-
-    virtual void replace_with (jit_value *value);
-
-    void replace_in_phi (jit_block *ablock, jit_block *with);
-
-    // we have a new internal list, but we want to stay compatible with jit_value
-    jit_use * first_use (void) const { return jit_value::first_use (); }
-
-    std::size_t use_count (void) const { return jit_value::use_count (); }
-
-    // if a block is alive, then it might be visited during execution
-    bool alive (void) const { return m_alive; }
-
-    void mark_alive (void) { m_alive = true; }
-
-    // If we can merge with a successor, do so and return the now empty block
-    jit_block * maybe_merge ();
-
-    // merge another block into this block, leaving the merge block empty
-    void merge (jit_block& merge);
-
-    const std::string& name (void) const { return m_name; }
-
-    jit_instruction * prepend (jit_instruction *instr);
-
-    jit_instruction * prepend_after_phi (jit_instruction *instr);
-
-    template <typename T>
-    T * append (T *instr)
-    {
-      internal_append (instr);
-      return instr;
-    }
-
-    jit_instruction * insert_before (iterator loc, jit_instruction *instr);
-
-    jit_instruction * insert_before (jit_instruction *loc, jit_instruction *instr)
-    {
-      return insert_before (loc->location (), instr);
-    }
-
-    jit_instruction * insert_after (iterator loc, jit_instruction *instr);
-
-    jit_instruction * insert_after (jit_instruction *loc, jit_instruction *instr)
-    {
-      return insert_after (loc->location (), instr);
-    }
-
-    iterator remove (iterator iter)
-    {
-      jit_instruction *instr = *iter;
-      iter = m_instructions.erase (iter);
-      instr->stash_parent (0, m_instructions.end ());
-      return iter;
-    }
-
-    jit_terminator * terminator (void) const;
-
-    // is the jump from pred alive?
-    bool branch_alive (jit_block *asucc) const;
-
-    jit_block * successor (std::size_t i) const;
-
-    std::size_t successor_count (void) const;
-
-    iterator begin (void) { return m_instructions.begin (); }
-
-    const_iterator begin (void) const { return m_instructions.begin (); }
-
-    iterator end (void) { return m_instructions.end (); }
-
-    const_iterator end (void) const { return m_instructions.end (); }
-
-    iterator phi_begin (void);
-
-    iterator phi_end (void);
-
-    iterator nonphi_begin (void);
-
-    // must label before id is valid
-    std::size_t id (void) const { return m_id; }
-
-    // dominance frontier
-    const df_set& df (void) const { return m_df; }
-
-    df_iterator df_begin (void) const { return m_df.begin (); }
-
-    df_iterator df_end (void) const { return m_df.end (); }
-
-    // label with a RPO walk
-    void label (void)
-    {
-      std::size_t number = 0;
-      label (m_visit_count, number);
-    }
-
-    void label (std::size_t avisit_count, std::size_t& number);
-
-    // See for idom computation algorithm
-    // Cooper, Keith D.; Harvey, Timothy J; and Kennedy, Ken (2001).
-    // "A Simple, Fast Dominance Algorithm"
-    void compute_idom (jit_block& entry_block)
-    {
-      bool changed;
-      entry_block.m_idom = &entry_block;
-      do
-        changed = update_idom (m_visit_count);
-      while (changed);
-    }
-
-    // compute dominance frontier
-    void compute_df (void)
-    {
-      compute_df (m_visit_count);
-    }
-
-    void create_dom_tree (void)
-    {
-      create_dom_tree (m_visit_count);
-    }
-
-    jit_block * dom_successor (std::size_t idx) const
-    {
-      return m_dom_succ[idx];
-    }
-
-    std::size_t dom_successor_count (void) const
-    {
-      return m_dom_succ.size ();
-    }
-
-    // call pop_variable on all instructions
-    void pop_all (void);
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const;
-
-    jit_block * maybe_split (jit_factory& factory, jit_block_list& blocks,
-                             jit_block *asuccessor);
-
-    jit_block * maybe_split (jit_factory& factory, jit_block_list& blocks,
-                             jit_block& asuccessor)
-    {
-      return maybe_split (factory, blocks, &asuccessor);
-    }
-
-    // print dominator infomration
-    std::ostream& print_dom (std::ostream& os) const;
-
-    virtual std::ostream& short_print (std::ostream& os) const
-    {
-      os << m_name;
-      if (m_id != NO_ID)
-        os << m_id;
-      else
-        os << '!';
-      return os;
-    }
-
-    llvm::BasicBlock * to_llvm (void) const;
-
-    std::list<jit_block *>::iterator location (void) const
-    { return m_location; }
-
-    void stash_location (std::list<jit_block *>::iterator alocation)
-    { m_location = alocation; }
-
-    // used to prevent visiting the same node twice in the graph
-    std::size_t visit_count (void) const { return m_visit_count; }
-
-    // check if this node has been visited yet at the given visit count.
-    // If we have not been visited yet, mark us as visited.
-    bool visited (std::size_t avisit_count)
-    {
-      if (m_visit_count <= avisit_count)
-        {
-          m_visit_count = avisit_count + 1;
-          return false;
-        }
-
-      return true;
-    }
-
-    jit_instruction * front (void) { return m_instructions.front (); }
-
-    jit_instruction * back (void) { return m_instructions.back (); }
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    void internal_append (jit_instruction *instr);
-
-    void compute_df (std::size_t avisit_count);
-
-    bool update_idom (std::size_t avisit_count);
-
-    void create_dom_tree (std::size_t avisit_count);
-
-    static jit_block * idom_intersect (jit_block *i, jit_block *j);
-
-    std::size_t m_visit_count;
-    std::size_t m_id;
-    jit_block *m_idom;
-    df_set m_df;
-    std::vector<jit_block *> m_dom_succ;
-    std::string m_name;
-    instruction_list m_instructions;
-    bool m_alive;
-    std::list<jit_block *>::iterator m_location;
-  };
-
-  // keeps track of phi functions that use a block on incoming edges
-  class
-  jit_phi_incoming : public jit_internal_node<jit_block, jit_phi_incoming>
-  {
-  public:
-
-    jit_phi_incoming (void) : m_user (0) { }
-
-    jit_phi_incoming (jit_phi *auser) : m_user (auser) { }
-
-    jit_phi_incoming (const jit_phi_incoming& use)
-    {
-      *this = use;
-    }
-
-    jit_phi_incoming& operator= (const jit_phi_incoming& use)
-    {
-      stash_value (use.value ());
-      m_user = use.m_user;
-      return *this;
-    }
-
-    jit_phi * user (void) const { return m_user; }
-
-    jit_block * user_parent (void) const;
-
-  private:
-
-    jit_phi *m_user;
-  };
-
-  // A non-ssa variable
-  class
-  jit_variable : public jit_value
-  {
-  public:
-
-    jit_variable (const std::string& aname) : m_name (aname), m_last_use (0) { }
-
-    const std::string& name (void) const { return m_name; }
-
-    // manipulate the value_stack, for use during SSA construction.  The top of
-    // the value stack represents the current value for this variable
-    bool has_top (void) const
-    {
-      return ! value_stack.empty ();
-    }
-
-    jit_value * top (void) const
-    {
-      return value_stack.top ();
-    }
-
-    void push (jit_instruction *v)
-    {
-      value_stack.push (v);
-      m_last_use = v;
-    }
-
-    void pop (void)
-    {
-      value_stack.pop ();
-    }
-
-    jit_instruction * last_use (void) const
-    {
-      return m_last_use;
-    }
-
-    void stash_last_use (jit_instruction *instr)
-    {
-      m_last_use = instr;
-    }
-
-    // blocks in which we are used
-    void use_blocks (jit_block::df_set& result)
-    {
-      jit_use *use = first_use ();
-      while (use)
-        {
-          result.insert (use->user_parent ());
-          use = use->next ();
-        }
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      return print_indent (os, indent) << m_name;
-    }
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    std::string m_name;
-    std::stack<jit_value *> value_stack;
-    jit_instruction *m_last_use;
-  };
-
-  class
-  jit_assign_base : public jit_instruction
-  {
-  public:
-
-    jit_assign_base (jit_variable *adest)
-      : jit_instruction (), m_dest (adest)
-    { }
-
-    jit_assign_base (jit_variable *adest, std::size_t npred)
-      : jit_instruction (npred), m_dest (adest)
-    { }
-
-    jit_assign_base (jit_variable *adest, jit_value *arg0, jit_value *arg1)
-      : jit_instruction (arg0, arg1), m_dest (adest)
-    { }
-
-    jit_variable * dest (void) const { return m_dest; }
-
-    virtual void push_variable (void)
-    {
-      m_dest->push (this);
-    }
-
-    virtual void pop_variable (void)
-    {
-      m_dest->pop ();
-    }
-
-    virtual std::ostream& short_print (std::ostream& os) const
-    {
-      if (type ())
-        jit_print (os, type ()) << ": ";
-
-      dest ()->short_print (os);
-      return os << '#' << id ();
-    }
-
-  private:
-
-    jit_variable *m_dest;
-  };
-
-  class
-  jit_assign : public jit_assign_base
-  {
-  public:
-
-    jit_assign (jit_variable *adest, jit_value *asrc)
-      : jit_assign_base (adest, adest, asrc), m_artificial (false)
-    { }
-
-    jit_value * overwrite (void) const
-    {
-      return argument (0);
-    }
-
-    jit_value * src (void) const
-    {
-      return argument (1);
-    }
-
-    // Variables don't get modified in an SSA, but COW requires we
-    // modify variables.  An artificial assign is for when a variable
-    // gets modified.  We need an assign in the SSA, but the reference
-    // counts shouldn't be updated.
-
-    bool artificial (void) const { return m_artificial; }
-
-    void mark_artificial (void) { m_artificial = true; }
-
-    virtual bool infer (void)
-    {
-      jit_type *stype = src ()->type ();
-      if (stype != type())
-        {
-          stash_type (stype);
-          return true;
-        }
-
-      return false;
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent) << *this << " = " << *src ();
-
-      if (artificial ())
-        os << " [artificial]";
-
-      return os;
-    }
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    bool m_artificial;
-  };
-
-  class
-  jit_phi : public jit_assign_base
-  {
-  public:
-
-    jit_phi (jit_variable *adest, std::size_t npred)
-      : jit_assign_base (adest, npred)
-    {
-      m_incoming.reserve (npred);
-    }
-
-    // removes arguments form dead incoming jumps
-    bool prune (void);
-
-    void add_incoming (jit_block *from, jit_value *value)
-    {
-      push_argument (value);
-      m_incoming.push_back (jit_phi_incoming (this));
-      m_incoming[m_incoming.size () - 1].stash_value (from);
-    }
-
-    jit_block * incoming (std::size_t i) const
-    {
-      return m_incoming[i].value ();
-    }
-
-    llvm::BasicBlock * incoming_llvm (std::size_t i) const
-    {
-      return incoming (i)->to_llvm ();
-    }
-
-    virtual void construct_ssa (void) { }
-
-    virtual bool infer (void);
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      std::stringstream ss;
-      print_indent (ss, indent);
-      short_print (ss) << " phi ";
-      std::string ss_str = ss.str ();
-      std::string indent_str (ss_str.size (), ' ');
-      os << ss_str;
-
-      for (std::size_t i = 0; i < argument_count (); ++i)
-        {
-          if (i > 0)
-            os << indent_str;
-          os << "| ";
-
-          os << *incoming (i) << " -> ";
-          os << *argument (i);
-
-          if (i + 1 < argument_count ())
-            os << std::endl;
-        }
-
-      return os;
-    }
-
-    llvm::PHINode * to_llvm (void) const;
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    std::vector<jit_phi_incoming> m_incoming;
-  };
-
-  class
-  jit_terminator : public jit_instruction
-  {
-  public:
-
-    template <typename ...Args>
-    jit_terminator (std::size_t asuccessor_count, Args... args)
-      : jit_instruction (args...),
-        m_alive (asuccessor_count, false) { }
-
-    jit_block * successor (std::size_t idx = 0) const
-    {
-      return static_cast<jit_block *> (argument (idx));
-    }
-
-    llvm::BasicBlock * successor_llvm (std::size_t idx = 0) const
-    {
-      return successor (idx)->to_llvm ();
-    }
-
-    std::size_t successor_index (const jit_block *asuccessor) const;
-
-    std::ostream& print_successor (std::ostream& os, std::size_t idx = 0) const
-    {
-      if (alive (idx))
-        os << "[live] ";
-      else
-        os << "[dead] ";
-
-      return successor (idx)->short_print (os);
-    }
-
-    // Check if the jump to successor is live
-    bool alive (const jit_block *asuccessor) const
-    {
-      return alive (successor_index (asuccessor));
-    }
-
-    bool alive (std::size_t idx) const { return m_alive[idx]; }
-
-    bool alive (int idx) const { return m_alive[idx]; }
-
-    std::size_t successor_count (void) const { return m_alive.size (); }
-
-    virtual bool infer (void);
-
-    llvm::TerminatorInst * to_llvm (void) const;
-
-  protected:
-
-    virtual bool check_alive (std::size_t) const { return true; }
-
-  private:
-
-    std::vector<bool> m_alive;
-  };
-
-  class
-  jit_branch : public jit_terminator
-  {
-  public:
-
-    jit_branch (jit_block *succ) : jit_terminator (1, succ) { }
-
-    virtual std::size_t successor_count (void) const { return 1; }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent) << "branch: ";
-      return print_successor (os);
-    }
-
-    JIT_VALUE_ACCEPT;
-  };
-
-  class
-  jit_cond_branch : public jit_terminator
-  {
-  public:
-
-    jit_cond_branch (jit_value *c, jit_block *ctrue, jit_block *cfalse)
-      : jit_terminator (2, ctrue, cfalse, c) { }
-
-    jit_value * cond (void) const { return argument (2); }
-
-    std::ostream& print_cond (std::ostream& os) const
-    {
-      return cond ()->short_print (os);
-    }
-
-    llvm::Value * cond_llvm (void) const
-    {
-      return cond ()->to_llvm ();
-    }
-
-    virtual std::size_t successor_count (void) const { return 2; }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent) << "cond_branch: ";
-      print_cond (os) << ", ";
-      print_successor (os, 0) << ", ";
-      return print_successor (os, 1);
-    }
-
-    JIT_VALUE_ACCEPT;
-  };
-
-  class
-  jit_call : public jit_instruction
-  {
-  public:
-
-    jit_call (const jit_operation& (*aoperation) (void))
-      : m_operation (aoperation ())
-    {
-      const jit_function& ol = overload ();
-      if (ol.valid ())
-        stash_type (ol.result ());
-    }
-
-    jit_call (const jit_operation& aoperation) : m_operation (aoperation)
-    {
-      const jit_function& ol = overload ();
-      if (ol.valid ())
-        stash_type (ol.result ());
-    }
-
-    template <typename ...Args>
-    jit_call (const jit_operation& aoperation,
-              jit_value * arg1, Args... other_args)
-      : jit_instruction (arg1, other_args...), m_operation (aoperation)
-    { }
-
-    template <typename ...Args>
-    jit_call (const jit_operation& (*aoperation) (void),
-              jit_value * arg1, Args... other_args)
-      : jit_instruction (arg1, other_args...), m_operation (aoperation ())
-    { }
-
-    jit_call (const jit_operation& aoperation,
-              const std::vector<jit_value *>& args)
-      : jit_instruction (args), m_operation (aoperation)
-    { }
-
-    const jit_operation& operation (void) const { return m_operation; }
-
-    bool can_error (void) const
-    {
-      return overload ().can_error ();
-    }
-
-    const jit_function& overload (void) const
-    {
-      return m_operation.overload (argument_types ());
-    }
-
-    virtual bool needs_release (void) const;
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent);
-
-      if (use_count ())
-        short_print (os) << " = ";
-      os << "call " << m_operation.name () << " (";
-
-      for (std::size_t i = 0; i < argument_count (); ++i)
-        {
-          print_argument (os, i);
-          if (i + 1 < argument_count ())
-            os << ", ";
-        }
-      return os << ')';
-    }
-
-    virtual bool infer (void);
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    const jit_operation& m_operation;
-  };
-
-  // FIXME: This is just ugly...
-  // checks error_state, if error_state is false then goto the normal branch,
-  // otherwise goto the error branch
-  class
-  jit_error_check : public jit_terminator
-  {
-  public:
-
-    // Which variable is the error check for?
-    enum variable
-    {
-      var_error_state,
-      var_interrupt
-    };
-
-    static std::string variable_to_string (variable v);
-
-    jit_error_check (variable var, jit_call *acheck_for, jit_block *normal,
-                     jit_block *error)
-      : jit_terminator (2, error, normal, acheck_for), m_variable (var) { }
-
-    jit_error_check (variable var, jit_block *normal, jit_block *error)
-      : jit_terminator (2, error, normal), m_variable (var) { }
-
-    variable check_variable (void) const { return m_variable; }
-
-    bool has_check_for (void) const
-    {
-      return argument_count () == 3;
-    }
-
-    jit_call * check_for (void) const
-    {
-      assert (has_check_for ());
-      return static_cast<jit_call *> (argument (2));
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const;
-
-    JIT_VALUE_ACCEPT;
-
-  protected:
-
-    virtual bool check_alive (std::size_t idx) const
-    {
-      if (! has_check_for ())
-        return true;
-      return idx == 1 ? true : check_for ()->can_error ();
-    }
-
-  private:
-
-    variable m_variable;
-  };
-
-  // for now only handles the 1D case
-  class
-  jit_magic_end : public jit_instruction
-  {
-  public:
-
-    class
-    context
-    {
-    public:
-
-      context (void) : m_value (0), m_index (0), m_count (0) { }
-
-      context (jit_factory& factory, jit_value *avalue, std::size_t aindex,
-               std::size_t acount);
-
-      jit_value *m_value;
-      jit_const_index *m_index;
-      jit_const_index *m_count;
-    };
-
-    jit_magic_end (const std::vector<context>& full_context);
-
-    virtual bool infer (void);
-
-    const jit_function& overload () const;
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const;
-
-    context resolve_context (void) const;
-
-    virtual std::ostream& short_print (std::ostream& os) const
-    {
-      return os << "magic_end" << '#' << id ();
-    }
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    std::vector<context> m_contexts;
-  };
-
-  class
-  jit_extract_argument : public jit_assign_base
-  {
-  public:
-
-    jit_extract_argument (jit_type *atype, jit_variable *adest)
-      : jit_assign_base (adest)
-    {
-      stash_type (atype);
-    }
-
-    const std::string& name (void) const
-    {
-      return dest ()->name ();
-    }
-
-    const jit_function& overload (void) const
-    {
-      return jit_typeinfo::cast (type (), jit_typeinfo::get_any ());
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent);
-
-      return short_print (os) << " = extract " << name ();
-    }
-
-    JIT_VALUE_ACCEPT;
-  };
-
-  class
-  jit_store_argument : public jit_instruction
-  {
-  public:
-
-    jit_store_argument (jit_variable *var)
-      : jit_instruction (var), m_dest (var)
-    { }
-
-    const std::string& name (void) const
-    {
-      return m_dest->name ();
-    }
-
-    const jit_function& overload (void) const
-    {
-      return jit_typeinfo::cast (jit_typeinfo::get_any (), result_type ());
-    }
-
-    jit_value * result (void) const
-    {
-      return argument (0);
-    }
-
-    jit_type * result_type (void) const
-    {
-      return result ()->type ();
-    }
-
-    llvm::Value * result_llvm (void) const
-    {
-      return result ()->to_llvm ();
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      jit_value *res = result ();
-      print_indent (os, indent) << "store ";
-      m_dest->short_print (os);
-
-      if (! isa<jit_variable> (res))
-        {
-          os << " = ";
-          res->short_print (os);
-        }
-
-      return os;
-    }
-
-    JIT_VALUE_ACCEPT;
-
-  private:
-
-    jit_variable *m_dest;
-  };
-
-  class
-  jit_return : public jit_instruction
-  {
-  public:
-
-    jit_return (void) { }
-
-    jit_return (jit_value *retval) : jit_instruction (retval) { }
-
-    jit_value * result (void) const
-    {
-      return argument_count () ? argument (0) : nullptr;
-    }
-
-    jit_type * result_type (void) const
-    {
-      jit_value *res = result ();
-      return res ? res->type () : nullptr;
-    }
-
-    virtual std::ostream& print (std::ostream& os, std::size_t indent = 0) const
-    {
-      print_indent (os, indent) << "return";
-
-      if (result ())
-        os << ' ' << *result ();
-
-      return os;
-    }
-
-    JIT_VALUE_ACCEPT;
-  };
-
-  class
-  jit_ir_walker
-  {
-  public:
-
-    virtual ~jit_ir_walker (void) { }
-
-#define JIT_METH(clname)                        \
-    virtual void visit (jit_ ## clname&) = 0;
-
-    JIT_VISIT_IR_CLASSES;
-
-#undef JIT_METH
-  };
-
-  template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T, bool QUOTE>
-  void
-  jit_const<T, EXTRACT_T, PASS_T, QUOTE>::accept (jit_ir_walker& walker)
-  {
-    walker.visit (*this);
-  }
-
-#undef JIT_VALUE_ACCEPT
-}
-
-#endif
-
-#endif
--- a/libinterp/parse-tree/jit-typeinfo.cc	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2378 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-// defines required by llvm
-#define __STDC_LIMIT_MACROS
-#define __STDC_CONSTANT_MACROS
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined (HAVE_LLVM)
-
-#if defined (HAVE_LLVM_IR_VERIFIER_H)
-#  include <llvm/IR/Verifier.h>
-#else
-#  include <llvm/Analysis/Verifier.h>
-#endif
-
-#include <llvm/ExecutionEngine/ExecutionEngine.h>
-
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-#  include <llvm/IR/GlobalVariable.h>
-#  include <llvm/IR/LLVMContext.h>
-#  include <llvm/IR/Function.h>
-#  include <llvm/IR/Instructions.h>
-#  include <llvm/IR/Intrinsics.h>
-#else
-#  include <llvm/GlobalVariable.h>
-#  include <llvm/LLVMContext.h>
-#  include <llvm/Function.h>
-#  include <llvm/Instructions.h>
-#  include <llvm/Intrinsics.h>
-#endif
-
-#if defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
-#  include <llvm/Support/IRBuilder.h>
-#  elif defined(HAVE_LLVM_IR_IRBUILDER_H)
-#  include <llvm/IR/IRBuilder.h>
-#else
-#  include <llvm/IRBuilder.h>
-#endif
-
-#include <llvm/Support/raw_os_ostream.h>
-
-#include "jit-typeinfo.h"
-#include "pt-jit.h"
-#include "jit-ir.h"
-#include "ov.h"
-#include "ov-builtin.h"
-#include "ov-complex.h"
-#include "ov-scalar.h"
-#include "pager.h"
-#include "interpreter-private.h"
-
-namespace octave
-{
-  static llvm::LLVMContext& context = tree_jit::llvm_context;
-
-  std::ostream& jit_print (std::ostream& os, jit_type *atype)
-  {
-    if (! atype)
-      return os << "null";
-    return os << atype->name ();
-  }
-
-  // function that jit code calls
-  extern "C" void
-  octave_jit_print_any (const char *name, octave_base_value *obv)
-  {
-    obv->print_with_name (octave_stdout, name, true);
-  }
-
-  extern "C" void
-  octave_jit_print_scalar (const char *name, double value)
-  {
-    // FIXME: We should avoid allocating a new octave_scalar each time
-    octave_value ov (value);
-    ov.print_with_name (octave_stdout, name);
-  }
-
-  extern "C" octave_base_value*
-  octave_jit_binary_any_any (octave_value::binary_op op, octave_base_value *lhs,
-                             octave_base_value *rhs)
-  {
-    octave_value olhs (lhs, true);
-    octave_value orhs (rhs, true);
-    octave_value result = do_binary_op (op, olhs, orhs);
-    octave_base_value *rep = result.internal_rep ();
-    rep->grab ();
-    return rep;
-  }
-
-  extern "C" octave_idx_type
-  octave_jit_compute_nelem (double base, double limit, double inc)
-  {
-    range<double> rng (base, inc, limit);
-    return rng.numel ();
-  }
-
-  extern "C" void
-  octave_jit_release_any (octave_base_value *obv)
-  {
-    obv->release ();
-  }
-
-  extern "C" void
-  octave_jit_release_matrix (jit_matrix *m)
-  {
-    delete m->m_array;
-  }
-
-  extern "C" octave_base_value *
-  octave_jit_grab_any (octave_base_value *obv)
-  {
-    obv->grab ();
-    return obv;
-  }
-
-  extern "C" jit_matrix
-  octave_jit_grab_matrix (jit_matrix *m)
-  {
-    return *m->m_array;
-  }
-
-  extern "C" octave_base_value *
-  octave_jit_cast_any_matrix (jit_matrix *m)
-  {
-    octave_value ret (*m->m_array);
-    octave_base_value *rep = ret.internal_rep ();
-    rep->grab ();
-    delete m->m_array;
-
-    return rep;
-  }
-
-  extern "C" jit_matrix
-  octave_jit_cast_matrix_any (octave_base_value *obv)
-  {
-    NDArray m = obv->array_value ();
-    obv->release ();
-    return m;
-  }
-
-  extern "C" octave_base_value *
-  octave_jit_cast_any_range (jit_range *rng)
-  {
-    range<double> temp (*rng);
-    octave_value ret (temp);
-    octave_base_value *rep = ret.internal_rep ();
-    rep->grab ();
-
-    return rep;
-  }
-  extern "C" jit_range
-  octave_jit_cast_range_any (octave_base_value *obv)
-  {
-
-    jit_range r (obv->range_value ());
-    obv->release ();
-    return r;
-  }
-
-  extern "C" double
-  octave_jit_cast_scalar_any (octave_base_value *obv)
-  {
-    double ret = obv->double_value ();
-    obv->release ();
-    return ret;
-  }
-
-  extern "C" octave_base_value *
-  octave_jit_cast_any_scalar (double value)
-  {
-    return new octave_scalar (value);
-  }
-
-  extern "C" Complex
-  octave_jit_cast_complex_any (octave_base_value *obv)
-  {
-    Complex ret = obv->complex_value ();
-    obv->release ();
-    return ret;
-  }
-
-  extern "C" octave_base_value *
-  octave_jit_cast_any_complex (Complex c)
-  {
-    if (c.imag () == 0)
-      return new octave_scalar (c.real ());
-    else
-      return new octave_complex (c);
-  }
-
-  extern "C" void
-  octave_jit_err_nan_to_logical_conversion (void)
-  {
-    err_nan_to_logical_conversion ();
-  }
-
-  extern "C" void
-  octave_jit_ginvalid_index (void)
-  {
-    // FIXME: 0-argument form of err_invalid_index removed in
-    //        cset dd6345fd8a97.  Report -1 as the bad index for all
-    //        occurrences.
-    err_invalid_index (static_cast<octave_idx_type> (-1));
-  }
-
-  extern "C" void
-  octave_jit_gindex_range (int nd, int dim, octave_idx_type iext,
-                           octave_idx_type ext)
-  {
-    err_index_out_of_range (nd, dim, iext, ext);
-  }
-
-  extern "C" jit_matrix
-  octave_jit_paren_subsasgn_impl (jit_matrix *mat, octave_idx_type index,
-                                  double value)
-  {
-    NDArray *array = mat->m_array;
-    if (array->numel () < index)
-      array->resize1 (index);
-
-    double *data = array->fortran_vec ();
-    data[index - 1] = value;
-
-    mat->update ();
-    return *mat;
-  }
-
-  static void
-  make_indices (double *indices, octave_idx_type idx_count,
-                Array<idx_vector>& result)
-  {
-    result.resize (dim_vector (1, idx_count));
-    for (octave_idx_type i = 0; i < idx_count; ++i)
-      result(i) = idx_vector (indices[i]);
-  }
-
-  extern "C" double
-  octave_jit_paren_scalar (jit_matrix *mat, double *indices,
-                           octave_idx_type idx_count)
-  {
-    // FIXME: Replace this with a more optimal version
-    Array<idx_vector> idx;
-    make_indices (indices, idx_count, idx);
-
-    Array<double> ret = mat->m_array->index (idx);
-
-    return ret.xelem (0);
-  }
-
-  extern "C" jit_matrix
-  octave_jit_paren_scalar_subsasgn (jit_matrix *mat, double *indices,
-                                    octave_idx_type idx_count, double value)
-  {
-    // FIXME: Replace this with a more optimal version
-    jit_matrix ret;
-
-    Array<idx_vector> idx;
-    make_indices (indices, idx_count, idx);
-
-    Matrix temp (1, 1);
-    temp.xelem(0) = value;
-    mat->m_array->assign (idx, temp);
-    ret.update (mat->m_array);
-
-    return ret;
-  }
-
-  extern "C" jit_matrix
-  octave_jit_paren_subsasgn_matrix_range (jit_matrix *mat, jit_range *index,
-                                          double value)
-  {
-    NDArray *array = mat->m_array;
-    bool done = false;
-
-    // optimize for the simple case (no resizing and no errors)
-    if (array->jit_ref_count () == 1
-        && index->all_elements_are_ints ())
-      {
-        // this code is similar to idx_vector::fill, but we avoid allocating an
-        // idx_vector and its associated rep
-        octave_idx_type start = static_cast<octave_idx_type> (index->m_base)-1;
-        octave_idx_type step = static_cast<octave_idx_type> (index->m_inc);
-        octave_idx_type nelem = index->m_nelem;
-        octave_idx_type final = start + nelem * step;
-        if (step < 0)
-          {
-            step = -step;
-            std::swap (final, start);
-          }
-
-        if (start >= 0 && final < mat->m_slice_len)
-          {
-            done = true;
-
-            double *data = array->jit_slice_data ();
-            if (step == 1)
-              std::fill (data + start, data + start + nelem, value);
-            else
-              {
-                for (octave_idx_type i = start; i < final; i += step)
-                  data[i] = value;
-              }
-          }
-      }
-
-    if (! done)
-      {
-        idx_vector idx (*index);
-        NDArray avalue (dim_vector (1, 1));
-        avalue.xelem (0) = value;
-        array->assign (idx, avalue);
-      }
-
-    jit_matrix ret;
-    ret.update (array);
-    return ret;
-  }
-
-  extern "C" double
-  octave_jit_end_matrix (jit_matrix *mat, octave_idx_type idx,
-                         octave_idx_type count)
-  {
-    octave_idx_type ndim = mat->m_ndims;
-    if (ndim == count)
-      return mat->m_dimensions[idx];
-    else if (ndim > count)
-      {
-        if (idx == count - 1)
-          {
-            double ret = mat->m_dimensions[idx];
-            for (octave_idx_type i = idx + 1; i < ndim; ++i)
-              ret *= mat->m_dimensions[idx];
-            return ret;
-          }
-
-        return mat->m_dimensions[idx];
-      }
-    else // ndim < count
-      return idx < ndim ? mat->m_dimensions[idx] : 1;
-  }
-
-  extern "C" octave_base_value *
-  octave_jit_create_undef (void)
-  {
-    octave_value undef;
-    octave_base_value *ret = undef.internal_rep ();
-    ret->grab ();
-
-    return ret;
-  }
-
-  extern "C" Complex
-  octave_jit_complex_mul (Complex lhs, Complex rhs)
-  {
-    if (lhs.imag () == 0 && rhs.imag() == 0)
-      return Complex (lhs.real () * rhs.real (), 0);
-
-    return lhs * rhs;
-  }
-
-  extern "C" Complex
-  octave_jit_complex_div (Complex lhs, Complex rhs)
-  {
-    return lhs / rhs;
-  }
-
-  // FIXME: CP form src/xpow.cc
-  static inline int
-  xisint (double x)
-  {
-    return (math::x_nint (x) == x
-            && ((x >= 0 && x < std::numeric_limits<int>::max ())
-                || (x <= 0 && x > std::numeric_limits<int>::min ())));
-  }
-
-  extern "C" Complex
-  octave_jit_pow_scalar_scalar (double lhs, double rhs)
-  {
-    // FIXME: almost CP from src/xpow.cc
-    if (lhs < 0.0 && ! xisint (rhs))
-      return std::pow (Complex (lhs), rhs);
-    return std::pow (lhs, rhs);
-  }
-
-  extern "C" Complex
-  octave_jit_pow_complex_complex (Complex lhs, Complex rhs)
-  {
-    if (lhs.imag () == 0 && rhs.imag () == 0)
-      return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ());
-    return std::pow (lhs, rhs);
-  }
-
-  extern "C" Complex
-  octave_jit_pow_complex_scalar (Complex lhs, double rhs)
-  {
-    if (lhs.imag () == 0)
-      return octave_jit_pow_scalar_scalar (lhs.real (), rhs);
-    return std::pow (lhs, rhs);
-  }
-
-  extern "C" Complex
-  octave_jit_pow_scalar_complex (double lhs, Complex rhs)
-  {
-    if (rhs.imag () == 0)
-      return octave_jit_pow_scalar_scalar (lhs, rhs.real ());
-    return std::pow (lhs, rhs);
-  }
-
-  extern "C" void
-  octave_jit_print_matrix (jit_matrix *m)
-  {
-    octave_stdout << *m << std::endl;
-  }
-
-  OCTAVE_NORETURN static
-  void
-  err_bad_result (void)
-  {
-    error ("incorrect type information given to the JIT compiler");
-  }
-
-  // FIXME: Add support for multiple outputs
-  extern "C" octave_base_value *
-  octave_jit_call (octave_builtin::fcn fn, std::size_t nargin,
-                   octave_base_value **argin, jit_type *result_type)
-  {
-    octave_value_list ovl (nargin);
-    for (std::size_t i = 0; i < nargin; ++i)
-      ovl.xelem (i) = octave_value (argin[i]);
-
-    ovl = fn (ovl, 1);
-
-    // FIXME: Check result_type somehow
-    if (result_type)
-      {
-        if (ovl.length () < 1)
-          err_bad_result ();
-
-        octave_value result = ovl.xelem(0);
-        octave_base_value *ret = result.internal_rep ();
-        ret->grab ();
-        return ret;
-      }
-
-    if (! (ovl.empty ()
-           || (ovl.length () == 1 && ovl.xelem (0).is_undefined ())))
-      err_bad_result ();
-
-    return 0;
-  }
-
-
-  // -------------------- jit_range --------------------
-  bool
-  jit_range::all_elements_are_ints () const
-  {
-    range<double> r (*this);
-    return r.all_elements_are_ints ();
-  }
-
-  std::ostream&
-  operator<< (std::ostream& os, const jit_range& rng)
-  {
-    return os << "Range[" << rng.m_base << ", " << rng.m_limit
-              << ", " << rng.m_inc << ", " << rng.m_nelem << ']';
-  }
-
-
-  // -------------------- jit_matrix --------------------
-
-  std::ostream&
-  operator<< (std::ostream& os, const jit_matrix& mat)
-  {
-    return os << "Matrix[" << mat.m_ref_count << ", "
-              << mat.m_slice_data << ", " << mat.m_slice_len << ", "
-              << mat.m_dimensions << ", " << mat.m_array << ']';
-  }
-
-
-  // -------------------- jit_type --------------------
-
-  jit_type::jit_type (const std::string& aname, jit_type *aparent,
-                      llvm::Type *allvm_type, bool askip_paren, int aid)
-    : m_name (aname), m_parent (aparent), m_llvm_type (allvm_type), m_id (aid),
-      m_depth (aparent ? aparent->m_depth + 1 : 0), m_skip_paren (askip_paren)
-  {
-    std::memset (m_sret, 0, sizeof (m_sret));
-    std::memset (m_pointer_arg, 0, sizeof (m_pointer_arg));
-    std::memset (m_pack, 0, sizeof (m_pack));
-    std::memset (m_unpack, 0, sizeof (m_unpack));
-
-    for (std::size_t i = 0; i < jit_convention::length; ++i)
-      m_packed_type[i] = m_llvm_type;
-  }
-
-  llvm::Type *
-  jit_type::to_llvm_arg (void) const
-  {
-    return m_llvm_type ? m_llvm_type->getPointerTo () : nullptr;
-  }
-
-  jit_type*
-  jit_type_join (jit_type *lhs, jit_type *rhs)
-  {
-    // empty case
-    if (! lhs)
-      return rhs;
-
-    if (! rhs)
-      return lhs;
-
-    // check for a shared parent
-    while (lhs != rhs)
-      {
-        if (lhs->depth () > rhs->depth ())
-          lhs = lhs->parent ();
-        else if (lhs->depth () < rhs->depth ())
-          rhs = rhs->parent ();
-        else
-          {
-            // we MUST have depth > 0 as any is the base type of everything
-            do
-              {
-                lhs = lhs->parent ();
-                rhs = rhs->parent ();
-              }
-            while (lhs != rhs);
-          }
-      }
-    return lhs;
-  }
-
-
-  // -------------------- jit_function --------------------
-  jit_function::jit_function ()
-    : m_module (nullptr), m_llvm_function (nullptr), m_result (nullptr),
-      m_call_conv (jit_convention::length), m_can_error (false)
-  { }
-
-  jit_function::jit_function (const jit_module *amodule,
-                              jit_convention::type acall_conv,
-                              const llvm::Twine& aname, jit_type *aresult,
-                              const std::vector<jit_type *>& aargs)
-    : m_module (amodule), m_result (aresult), m_args (aargs),
-      m_call_conv (acall_conv), m_can_error (false)
-  {
-    llvm::SmallVector<llvm::Type *, 15> llvm_args;
-
-    llvm::Type *rtype = llvm::Type::getVoidTy (context);
-    if (m_result)
-      {
-        rtype = m_result->packed_type (m_call_conv);
-        if (sret ())
-          {
-            llvm_args.push_back (rtype->getPointerTo ());
-            rtype = llvm::Type::getVoidTy (context);
-          }
-      }
-
-    for (auto iter = m_args.cbegin (); iter != m_args.cend (); ++iter)
-      {
-        jit_type *ty = *iter;
-        assert (ty);
-        llvm::Type *argty = ty->packed_type (m_call_conv);
-        if (ty->pointer_arg (m_call_conv))
-          argty = argty->getPointerTo ();
-
-        llvm_args.push_back (argty);
-      }
-
-    llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false);
-    m_llvm_function = m_module->create_llvm_function (ft, aname);
-
-    if (sret ())
-      {
-#if defined (FUNCTION_ADDATTRIBUTE_ARG_IS_ATTRIBUTES)
-        llvm::AttrBuilder attr_builder;
-        attr_builder.addAttribute (llvm::Attributes::StructRet);
-        llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
-        m_llvm_function->addAttribute (1, attrs);
-#else
-        m_llvm_function->addAttribute (1, llvm::Attribute::StructRet);
-#endif
-      }
-
-    if (m_call_conv == jit_convention::internal)
-#if defined (FUNCTION_ADDFNATTR_ARG_IS_ATTRIBUTES)
-      m_llvm_function->addFnAttr (llvm::Attributes::AlwaysInline);
-#else
-      m_llvm_function->addFnAttr (llvm::Attribute::AlwaysInline);
-#endif
-  }
-
-  jit_function::jit_function (const jit_function& fn, jit_type *aresult,
-                              const std::vector<jit_type *>& aargs)
-    : m_module (fn.m_module), m_llvm_function (fn.m_llvm_function),
-      m_result (aresult), m_args (aargs), m_call_conv (fn.m_call_conv),
-      m_can_error (fn.m_can_error)
-  { }
-
-  jit_function::jit_function (const jit_function& fn)
-    : m_module (fn.m_module), m_llvm_function (fn.m_llvm_function),
-      m_result (fn.m_result), m_args (fn.m_args), m_call_conv (fn.m_call_conv),
-      m_can_error (fn.m_can_error)
-  { }
-
-  void
-  jit_function::erase (void)
-  {
-    if (! m_llvm_function)
-      return;
-
-    m_llvm_function->eraseFromParent ();
-    m_llvm_function = 0;
-  }
-
-  std::string
-  jit_function::name (void) const
-  {
-    return m_llvm_function->getName ();
-  }
-
-  llvm::BasicBlock *
-  jit_function::new_block (const std::string& aname,
-                           llvm::BasicBlock *insert_before)
-  {
-    return llvm::BasicBlock::Create (context, aname, m_llvm_function,
-                                     insert_before);
-  }
-
-  llvm::Value *
-  jit_function::call (llvm::IRBuilderD& builder,
-                      const std::vector<jit_value *>& in_args) const
-  {
-    if (! valid ())
-      throw jit_fail_exception ("Call not implemented");
-
-    assert (in_args.size () == m_args.size ());
-    std::vector<llvm::Value *> llvm_args (m_args.size ());
-    for (std::size_t i = 0; i < in_args.size (); ++i)
-      llvm_args[i] = in_args[i]->to_llvm ();
-
-    return call (builder, llvm_args);
-  }
-
-  llvm::Value *
-  jit_function::call (llvm::IRBuilderD& builder,
-                      const std::vector<llvm::Value *>& in_args) const
-  {
-    if (! valid ())
-      throw jit_fail_exception ("Call not implemented");
-
-    assert (in_args.size () == m_args.size ());
-    llvm::SmallVector<llvm::Value *, 10> llvm_args;
-    llvm_args.reserve (in_args.size () + sret ());
-
-    llvm::BasicBlock *insert_block = builder.GetInsertBlock ();
-    llvm::Function *parent = insert_block->getParent ();
-    assert (parent);
-
-    // Insert allocas inside the prelude block to prevent stack overflows
-    llvm::BasicBlock& prelude = parent->getEntryBlock ();
-    llvm::IRBuilder<> pre_builder (&prelude, prelude.begin ());
-
-    llvm::AllocaInst *sret_mem = nullptr;
-    if (sret ())
-      {
-        sret_mem = pre_builder.CreateAlloca (m_result->packed_type (m_call_conv));
-        llvm_args.push_back (sret_mem);
-      }
-
-    for (std::size_t i = 0; i < in_args.size (); ++i)
-      {
-        llvm::Value *arg = in_args[i];
-        jit_type::convert_fn convert = m_args[i]->pack (m_call_conv);
-        if (convert)
-          arg = convert (builder, arg);
-
-        if (m_args[i]->pointer_arg (m_call_conv))
-          {
-            llvm::Type *ty = m_args[i]->packed_type (m_call_conv);
-            llvm::Value *alloca = pre_builder.CreateAlloca (ty);
-            builder.CreateStore (arg, alloca);
-            arg = alloca;
-          }
-
-        llvm_args.push_back (arg);
-      }
-
-    llvm::CallInst *callinst = builder.CreateCall (m_llvm_function, llvm_args);
-    llvm::Value *ret = callinst;
-
-    if (sret ())
-      {
-#if defined (CALLINST_ADDATTRIBUTE_ARG_IS_ATTRIBUTES)
-        llvm::AttrBuilder attr_builder;
-        attr_builder.addAttribute(llvm::Attributes::StructRet);
-        llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
-        callinst->addAttribute (1, attrs);
-#else
-        callinst->addAttribute (1, llvm::Attribute::StructRet);
-#endif
-        ret = builder.CreateLoad (sret_mem);
-      }
-
-    if (m_result)
-      {
-        jit_type::convert_fn unpack = m_result->unpack (m_call_conv);
-        if (unpack)
-          ret = unpack (builder, ret);
-      }
-
-    return ret;
-  }
-
-  llvm::Value *
-  jit_function::argument (llvm::IRBuilderD& builder, std::size_t idx) const
-  {
-    assert (idx < m_args.size ());
-
-    // FIXME: We should be treating arguments like a list, not a vector.
-    // Shouldn't matter much for now, as the number of arguments shouldn't
-    // be much bigger than 4
-    auto iter = m_llvm_function->arg_begin ();
-    if (sret ())
-      ++iter;
-
-    for (std::size_t i = 0; i < idx; ++i, ++iter);
-
-    if (m_args[idx]->pointer_arg (m_call_conv))
-      return builder.CreateLoad (&*iter);
-
-    return &*iter;
-  }
-
-  void
-  jit_function::do_return (llvm::IRBuilderD& builder, llvm::Value *rval,
-                           bool verify)
-  {
-    assert (! rval == ! m_result);
-
-    if (rval)
-      {
-        jit_type::convert_fn convert = m_result->pack (m_call_conv);
-        if (convert)
-          rval = convert (builder, rval);
-
-        if (sret ())
-          {
-            builder.CreateStore (rval, &*(m_llvm_function->arg_begin ()));
-            builder.CreateRetVoid ();
-          }
-        else
-          builder.CreateRet (rval);
-      }
-    else
-      builder.CreateRetVoid ();
-
-    if (verify)
-      llvm::verifyFunction (*m_llvm_function);
-  }
-
-  std::ostream&
-  operator<< (std::ostream& os, const jit_function& fn)
-  {
-    llvm::Function *lfn = fn.to_llvm ();
-    os << "jit_function: cc=" << fn.m_call_conv;
-    llvm::raw_os_ostream llvm_out (os);
-    lfn->print (llvm_out);
-    llvm_out.flush ();
-    return os;
-  }
-
-  // -------------------- jit_operation --------------------
-  jit_operation::~jit_operation (void)
-  {
-    for (auto iter = m_generated.begin (); iter != m_generated.end (); ++iter)
-      {
-        delete iter->first;
-        delete iter->second;
-      }
-  }
-
-  void
-  jit_operation::add_overload (const jit_function& func,
-                               const std::vector<jit_type*>& args)
-  {
-    // Number of input arguments of the overload that is being registered
-    std::size_t nargs = args.size ();
-
-    if (nargs >= m_overloads.size ())
-      m_overloads.resize (nargs + 1);
-
-    Array<jit_function>& over = m_overloads[nargs];
-    dim_vector dv (over.dims ());
-    Array<octave_idx_type> idx = to_idx (args);
-    bool must_resize = false;
-
-    if (dv.length () != idx.numel ())
-      {
-        dv.resize (idx.numel ());
-        must_resize = true;
-      }
-
-    for (octave_idx_type i = 0; i < dv.length (); ++i)
-      if (dv(i) <= idx(i))
-        {
-          must_resize = true;
-          dv(i) = idx(i) + 1;
-        }
-
-    if (must_resize)
-      over.resize (dv);
-
-    over(idx) = func;
-  }
-
-  const jit_function&
-  jit_operation::overload (const std::vector<jit_type*>& types) const
-  {
-    // Number of input arguments of the overload that is being looked for
-    std::size_t nargs = types.size ();
-
-    static jit_function null_overload;
-    for (std::size_t i = 0; i < nargs; ++i)
-      if (! types[i])
-        return null_overload;
-
-    if (nargs >= m_overloads.size ())
-      return do_generate (types);
-
-    const Array<jit_function>& over = m_overloads[nargs];
-    dim_vector dv (over.dims ());
-    Array<octave_idx_type> idx = to_idx (types);
-    for (octave_idx_type i = 0; i < dv.length (); ++i)
-      if (idx(i) >= dv(i))
-        return do_generate (types);
-
-    const jit_function& ret = over(idx);
-    if (! ret.valid ())
-      return do_generate (types);
-
-    return ret;
-  }
-
-  Array<octave_idx_type>
-  jit_operation::to_idx (const std::vector<jit_type*>& types) const
-  {
-    octave_idx_type numel = types.size ();
-    numel = std::max (numel, static_cast<octave_idx_type> (2));
-
-    Array<octave_idx_type> idx (dim_vector (1, numel));
-    for (octave_idx_type i = 0;
-         i < static_cast<octave_idx_type> (types.size ());
-         ++i)
-      idx(i) = types[i]->type_id ();
-
-    if (types.size () == 0)
-      idx(0) = idx(1) = 0;
-    if (types.size () == 1)
-      {
-        idx(1) = idx(0);
-        idx(0) = 0;
-      }
-
-    return idx;
-  }
-
-  const jit_function&
-  jit_operation::do_generate (const signature_vec& types) const
-  {
-    static jit_function null_overload;
-    generated_map::const_iterator find = m_generated.find (&types);
-    if (find != m_generated.end ())
-      {
-        if (find->second)
-          return *find->second;
-        else
-          return null_overload;
-      }
-
-    jit_function *ret = generate (types);
-    m_generated[new signature_vec (types)] = ret;
-    return ret ? *ret : null_overload;
-  }
-
-  jit_function *
-  jit_operation::generate (const signature_vec&) const
-  {
-    return 0;
-  }
-
-  bool
-  jit_operation::signature_cmp::operator () (const signature_vec *lhs,
-                                             const signature_vec *rhs) const
-  {
-    const signature_vec& l = *lhs;
-    const signature_vec& r = *rhs;
-
-    if (l.size () < r.size ())
-      return true;
-    else if (l.size () > r.size ())
-      return false;
-
-    for (std::size_t i = 0; i < l.size (); ++i)
-      {
-        if (l[i]->type_id () < r[i]->type_id ())
-          return true;
-        else if (l[i]->type_id () > r[i]->type_id ())
-          return false;
-      }
-
-    return false;
-  }
-
-  // -------------------- jit_index_operation --------------------
-  jit_function *
-  jit_index_operation::generate (const signature_vec& types) const
-  {
-    if (types.size () > 2 && types[0] == jit_typeinfo::get_matrix ())
-      {
-        // indexing a matrix with scalars
-        jit_type *scalar = jit_typeinfo::get_scalar ();
-        for (std::size_t i = 1; i < types.size (); ++i)
-          if (types[i] != scalar)
-            return 0;
-
-        return generate_matrix (types);
-      }
-
-    return 0;
-  }
-
-  llvm::Value *
-  jit_index_operation::create_arg_array (llvm::IRBuilderD& builder,
-                                         const jit_function& fn,
-                                         std::size_t start_idx,
-                                         std::size_t end_idx) const
-  {
-    std::size_t n = end_idx - start_idx;
-    llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
-    llvm::ArrayType *array_t = llvm::ArrayType::get (scalar_t, n);
-    llvm::Value *array = llvm::UndefValue::get (array_t);
-    for (std::size_t i = start_idx; i < end_idx; ++i)
-      {
-        llvm::Value *idx = fn.argument (builder, i);
-        array = builder.CreateInsertValue (array, idx, i - start_idx);
-      }
-
-    llvm::Value *array_mem = builder.CreateAlloca (array_t);
-    builder.CreateStore (array, array_mem);
-    return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ());
-  }
-
-  // -------------------- jit_paren_subsref --------------------
-
-  jit_paren_subsref::jit_paren_subsref (const jit_typeinfo& ti)
-    : jit_index_operation (ti, "()subsref"), m_paren_scalar (nullptr)
-  { }
-
-  jit_paren_subsref::~jit_paren_subsref (void)
-  {
-    delete m_paren_scalar;
-  }
-
-  jit_function *
-  jit_paren_subsref::generate_matrix (const signature_vec& types) const
-  {
-    if (m_paren_scalar == nullptr)
-      panic_impossible ();
-
-    std::stringstream ss;
-    ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1);
-
-    // FIXME: Where will this be deleted?
-    jit_function *fn = new jit_function
-      (m_typeinfo.create_internal (ss.str (), m_typeinfo.m_scalar, types));
-
-    fn->mark_can_error ();
-    llvm::BasicBlock *body = fn->new_block ();
-    llvm::IRBuilder<> builder (body);
-
-    llvm::Value *array = create_arg_array (builder, *fn, 1, types.size ());
-    llvm::Value *nelem = llvm::ConstantInt::get (m_typeinfo.m_index_t,
-                                                 types.size () - 1);
-    llvm::Value *mat = fn->argument (builder, 0);
-    llvm::Value *ret = m_paren_scalar->call (builder, mat, array, nelem);
-    fn->do_return (builder, ret);
-    return fn;
-  }
-
-  void
-  jit_paren_subsref::init_paren_scalar ()
-  {
-    std::vector<jit_type *> types (3);
-    types[0] = m_typeinfo.m_matrix;
-    types[1] = m_typeinfo.m_scalar_ptr;
-    types[2] = m_typeinfo.m_index;
-
-    m_paren_scalar = new jit_function
-      (m_typeinfo.create_external (&octave_jit_paren_scalar,
-                                   "octave_jit_paren_scalar",
-                                   m_typeinfo.m_scalar, types));
-
-    m_paren_scalar->mark_can_error ();
-  }
-
-  // -------------------- jit_paren_subsasgn --------------------
-
-  jit_paren_subsasgn::jit_paren_subsasgn (const jit_typeinfo& ti)
-    : jit_index_operation (ti, "()subsasgn"), m_paren_scalar (nullptr)
-  { }
-
-  jit_paren_subsasgn::~jit_paren_subsasgn (void)
-  {
-    delete m_paren_scalar;
-  }
-
-  jit_function *
-  jit_paren_subsasgn::generate_matrix (const signature_vec& types) const
-  {
-    if (m_paren_scalar == nullptr)
-      panic_impossible ();
-
-    std::stringstream ss;
-    ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2);
-
-    // FIXME: Where will this be deleted?
-    jit_function *fn = new jit_function
-      (m_typeinfo.create_internal (ss.str (), m_typeinfo.m_matrix, types));
-
-    fn->mark_can_error ();
-    llvm::BasicBlock *body = fn->new_block ();
-    llvm::IRBuilder<> builder (body);
-
-    llvm::Value *array = create_arg_array (builder, *fn, 1, types.size () - 1);
-    llvm::Value *nelem = llvm::ConstantInt::get (m_typeinfo.m_index_t,
-                                                 types.size () - 2);
-
-    llvm::Value *mat = fn->argument (builder, 0);
-    llvm::Value *value = fn->argument (builder, types.size () - 1);
-    llvm::Value *ret = m_paren_scalar->call (builder, mat, array, nelem, value);
-    fn->do_return (builder, ret);
-
-    return fn;
-  }
-
-  void
-  jit_paren_subsasgn::init_paren_scalar ()
-  {
-    std::vector<jit_type *> types (4);
-    types[0] = m_typeinfo.m_matrix;
-    types[1] = m_typeinfo.m_scalar_ptr;
-    types[2] = m_typeinfo.m_index;
-    types[3] = m_typeinfo.m_scalar;
-
-    m_paren_scalar = new jit_function
-      (m_typeinfo.create_external (&octave_jit_paren_scalar_subsasgn,
-                                   "octave_jit_paren_scalar",
-                                   m_typeinfo.m_matrix, types));
-
-    m_paren_scalar->mark_can_error ();
-  }
-
-
-  // -------------------- jit_typeinfo --------------------
-
-  bool jit_typeinfo::s_in_construction = false;
-
-  // Static method that holds the singleton instance
-  jit_typeinfo&
-  jit_typeinfo::instance (void)
-  {
-    if (s_in_construction)
-      // This state is typically reached when the constructor calls one
-      // of the static methods of the singleton class...
-      panic_impossible ();
-
-    static jit_typeinfo typeinfo;
-    return typeinfo;
-  }
-
-  jit_typeinfo::~jit_typeinfo (void)
-  {
-    while (! m_id_to_type.empty ())
-      {
-        delete m_id_to_type.back ();
-        m_id_to_type.pop_back ();
-      }
-
-    delete m_builder_ptr;
-    delete m_base_jit_module;
-  }
-
-  // wrap function names to simplify jit_typeinfo::create_external
-#define JIT_FN(fn) &fn, #fn
-
-  jit_typeinfo::jit_typeinfo (void)
-    : paren_subsref_fn (*this),
-      paren_subsasgn_fn (*this),
-      m_next_id (0),
-      m_grab_fn ("grab"),
-      m_release_fn ("release"),
-      m_destroy_fn ("destroy"),
-      m_print_fn ("print"),
-      m_for_init_fn ("for_init"),
-      m_for_check_fn ("for_check"),
-      m_for_index_fn ("for_index"),
-      m_logically_true_fn ("logically_true"),
-      m_make_range_fn ("make_range"),
-      m_end1_fn ("end1"),
-      m_end_fn ("end"),
-      m_create_undef_fn ("create_undef"),
-      m_base_jit_module (new jit_module ("octaveJITBaseModule")),
-      m_builder_ptr (new llvm::IRBuilderD (context)),
-      // FIXME: Use a pointer directly in the constructor, and get rid of this
-      m_builder (*m_builder_ptr)
-  {
-    s_in_construction = true;
-
-    // ----- Register basic JIT types -----
-
-    // FIXME: It seems that our type lattice is not really a lattice
-    //        since any and any_ptr have no common upper_bound (?!?)
-
-    // jit_types: "any"     < (nullptr)
-    //            "any_ptr" < (nullptr)
-    m_any_t = llvm::StructType::create (context, "octave_base_value");
-    m_any_t = m_any_t->getPointerTo ();
-    m_any = do_register_new_type ("any", nullptr, m_any_t);
-    m_any_ptr = do_register_new_type ("any_ptr", nullptr,
-                                      m_any_t->getPointerTo ());
-
-    // jit_types: "scalar"     < "complex" < "any"
-    //       and: "scalar_ptr" < (nullptr)
-    // FIXME: what about sing-precision floats ???
-    // FIXME: shouldn't we make scalar_ptr a sub_type of any_ptr ?
-    m_scalar_t = llvm::Type::getDoubleTy (context);
-    m_complex_t = llvm::ArrayType::get (m_scalar_t, 2);
-    m_complex = do_register_new_type ("complex", m_any, m_complex_t);
-    m_scalar = do_register_new_type ("scalar", m_complex, m_scalar_t);
-    m_scalar_ptr = do_register_new_type ("scalar_ptr", nullptr,
-                                         m_scalar_t->getPointerTo ());
-
-    // jit_type: "bool" < "any"
-    m_bool_t = llvm::Type::getInt1Ty (context);
-    m_boolean = do_register_new_type ("bool", m_any, m_bool_t);
-
-    // jit_types: "int8", "int16", "int32", "int64" < "any"
-    m_ints[ 8] = do_register_new_type ("int8",  m_any,
-                                       llvm::Type::getIntNTy (context,  8));
-    m_ints[16] = do_register_new_type ("int16", m_any,
-                                       llvm::Type::getIntNTy (context, 16));
-    m_ints[32] = do_register_new_type ("int32", m_any,
-                                       llvm::Type::getIntNTy (context, 32));
-    m_ints[64] = do_register_new_type ("int64", m_any,
-                                       llvm::Type::getIntNTy (context, 64));
-
-    // jit_type: "string" < "any"
-    m_string_t = llvm::Type::getInt8Ty (context);
-    m_string_t = m_string_t->getPointerTo ();
-    m_string = do_register_new_type ("string", m_any, m_string_t);
-
-    // jit_type: "index" < "any"
-    m_index_t = llvm::Type::getIntNTy (context, sizeof (octave_idx_type) * 8);
-    m_index = do_register_new_type ("index", m_any, m_index_t);
-
-    // jit_type: "range" < "any"
-    m_range_t = llvm::StructType::create (context, "range");
-    {
-      std::vector<llvm::Type *> range_contents (4, m_scalar_t);
-      range_contents[3] = m_index_t;
-      m_range_t->setBody (range_contents);
-    }
-    m_range = do_register_new_type ("range", m_any, m_range_t);
-
-    // jit_type: "matrix" < "any"
-    m_matrix_t = llvm::StructType::create (context, "matrix");
-    {
-      llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8);
-      llvm::Type *matrix_contents[5];
-      matrix_contents[0] = refcount_t->getPointerTo ();
-      matrix_contents[1] = m_scalar_t->getPointerTo ();
-      matrix_contents[2] = m_index_t;
-      matrix_contents[3] = m_index_t->getPointerTo ();
-      matrix_contents[4] = m_string_t;
-      m_matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5));
-    }
-    m_matrix = do_register_new_type ("matrix", m_any, m_matrix_t);
-
-    // ----- Specify calling conventions -----
-
-    // complex_ret is what is passed to C functions
-    // in order to get calling convention right
-    m_complex_ret = llvm::StructType::create (context, "complex_ret");
-    {
-      llvm::Type *cmplx_inner_cont[] = {m_scalar_t, m_scalar_t};
-      llvm::StructType *cmplx_inner = llvm::StructType::create (cmplx_inner_cont);
-      llvm::Type *contents[] = {cmplx_inner};
-      m_complex_ret->setBody (contents);
-    }
-
-    // FIXME: We should detect architecture and do something sane
-    //        based on that here we assume x86 or x86_64
-    m_matrix->mark_sret (jit_convention::external);
-    m_matrix->mark_pointer_arg (jit_convention::external);
-
-    m_range->mark_sret (jit_convention::external);
-    m_range->mark_pointer_arg (jit_convention::external);
-
-    m_complex->set_pack (jit_convention::external,
-                         &jit_typeinfo::pack_complex);
-    m_complex->set_unpack (jit_convention::external,
-                           &jit_typeinfo::unpack_complex);
-    m_complex->set_packed_type (jit_convention::external, m_complex_ret);
-
-    if (sizeof (void *) == 4)
-      m_complex->mark_sret (jit_convention::external);
-
-    paren_subsref_fn.init_paren_scalar ();
-    paren_subsasgn_fn.init_paren_scalar ();
-
-    // bind global variables
-    m_lerror_state = m_base_jit_module->create_global_variable (m_bool_t, false,
-                                                                "error_state");
-
-    m_base_jit_module->add_global_mapping (m_lerror_state, &error_state);
-
-    // sig_atomic_type is going to be some sort of integer
-    m_sig_atomic_type = llvm::Type::getIntNTy (context,
-                                               sizeof(sig_atomic_t) * 8);
-
-    m_loctave_interrupt_state = m_base_jit_module->create_global_variable
-      (m_sig_atomic_type, false, "octave_interrupt_state");
-
-    m_base_jit_module->add_global_mapping (m_loctave_interrupt_state,
-                                           &octave_interrupt_state);
-
-    // generic call function
-    {
-      jit_type *int_t = do_get_intN (sizeof (octave_builtin::fcn) * 8);
-      m_any_call = create_external (JIT_FN (octave_jit_call), m_any, int_t,
-                                    int_t, m_any_ptr, int_t);
-    }
-
-    // any with anything is an any op
-    jit_function fn;
-    jit_type *binary_op_type = do_get_intN (sizeof (octave_value::binary_op) * 8);
-    llvm::Type *llvm_bo_type = binary_op_type->to_llvm ();
-    jit_function any_binary = create_external (JIT_FN (octave_jit_binary_any_any),
-                                               m_any, binary_op_type,
-                                               m_any, m_any);
-    any_binary.mark_can_error ();
-
-    for (std::size_t i = 0; i < octave_value::num_binary_ops; ++i)
-      {
-        octave_value::binary_op op = static_cast<octave_value::binary_op> (i);
-        std::string op_name = octave_value::binary_op_as_string (op);
-        m_binary_ops.push_back (jit_operation ("binary" + op_name));
-      }
-
-    for (std::size_t i = 0; i < octave_value::num_unary_ops; ++i)
-      {
-        octave_value::unary_op op = static_cast<octave_value::unary_op> (i);
-        std::string op_name = octave_value::unary_op_as_string (op);
-        m_unary_ops.push_back (jit_operation ("unary" + op_name));
-      }
-
-    for (int op = 0; op < octave_value::num_binary_ops; ++op)
-      {
-        const llvm::Twine& fn_name
-          = "octave_jit_binary_any_any_" + llvm::Twine (op);
-
-        fn = create_internal (fn_name, m_any, m_any, m_any);
-        fn.mark_can_error ();
-        llvm::BasicBlock *block = fn.new_block ();
-        m_builder.SetInsertPoint (block);
-        llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op,
-                           std::numeric_limits<octave_value::binary_op>::is_signed);
-        llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int);
-        llvm::Value *ret = any_binary.call (m_builder, op_as_llvm,
-                                            fn.argument (m_builder, 0),
-                                            fn.argument (m_builder, 1));
-        fn.do_return (m_builder, ret);
-        m_binary_ops[op].add_overload (fn);
-      }
-
-    // grab matrix
-    fn = create_external (JIT_FN (octave_jit_grab_matrix), m_matrix, m_matrix);
-    m_grab_fn.add_overload (fn);
-    m_grab_fn.add_overload (create_identity (m_scalar));
-    m_grab_fn.add_overload (create_identity (m_scalar_ptr));
-    m_grab_fn.add_overload (create_identity (m_any_ptr));
-    m_grab_fn.add_overload (create_identity (m_boolean));
-    m_grab_fn.add_overload (create_identity (m_complex));
-    m_grab_fn.add_overload (create_identity (m_index));
-
-    // release any
-    fn = create_external (JIT_FN (octave_jit_release_any), nullptr, m_any);
-    m_release_fn.add_overload (fn);
-
-    // release matrix
-    fn = create_external (JIT_FN (octave_jit_release_matrix), nullptr,
-                          m_matrix);
-    m_release_fn.add_overload (fn);
-
-    // destroy
-    m_destroy_fn = m_release_fn;
-    m_destroy_fn.add_overload (create_identity(m_scalar));
-    m_destroy_fn.add_overload (create_identity(m_boolean));
-    m_destroy_fn.add_overload (create_identity(m_index));
-    m_destroy_fn.add_overload (create_identity(m_complex));
-
-    // -------------------- scalar related operations --------------------
-
-    // now for binary scalar operations
-    add_binary_op (m_scalar, octave_value::op_add, llvm::Instruction::FAdd);
-    add_binary_op (m_scalar, octave_value::op_sub, llvm::Instruction::FSub);
-    add_binary_op (m_scalar, octave_value::op_mul, llvm::Instruction::FMul);
-    add_binary_op (m_scalar, octave_value::op_el_mul, llvm::Instruction::FMul);
-
-    add_binary_fcmp (m_scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT);
-    add_binary_fcmp (m_scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE);
-    add_binary_fcmp (m_scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ);
-    add_binary_fcmp (m_scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE);
-    add_binary_fcmp (m_scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT);
-    add_binary_fcmp (m_scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE);
-
-    // divide is annoying because it might error
-    fn = create_internal ("octave_jit_div_scalar_scalar", m_scalar, m_scalar,
-                          m_scalar);
-    fn.mark_can_error ();
-
-    llvm::BasicBlock *body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::BasicBlock *warn_block = fn.new_block ("warn");
-      llvm::BasicBlock *normal_block = fn.new_block ("normal");
-
-      llvm::Value *zero = llvm::ConstantFP::get (m_scalar_t, 0);
-      llvm::Value *check = m_builder.CreateFCmpUEQ (zero,
-                                                    fn.argument (m_builder, 1));
-      m_builder.CreateCondBr (check, warn_block, normal_block);
-
-      m_builder.SetInsertPoint (warn_block);
-      m_builder.CreateBr (normal_block);
-
-      m_builder.SetInsertPoint (normal_block);
-      llvm::Value *ret = m_builder.CreateFDiv (fn.argument (m_builder, 0),
-                                               fn.argument (m_builder, 1));
-      fn.do_return (m_builder, ret);
-    }
-    m_binary_ops[octave_value::op_div].add_overload (fn);
-    m_binary_ops[octave_value::op_el_div].add_overload (fn);
-
-    // ldiv is the same as div with the operators reversed
-    fn = mirror_binary (fn);
-    m_binary_ops[octave_value::op_ldiv].add_overload (fn);
-    m_binary_ops[octave_value::op_el_ldiv].add_overload (fn);
-
-    // In general, the result of scalar ^ scalar is a complex number.  We might
-    // be able to improve on this if we keep track of the range of values
-    // variables can take on.
-    fn = create_external (JIT_FN (octave_jit_pow_scalar_scalar), m_complex,
-                          m_scalar, m_scalar);
-    m_binary_ops[octave_value::op_pow].add_overload (fn);
-    m_binary_ops[octave_value::op_el_pow].add_overload (fn);
-
-    // now for unary scalar operations
-    // FIXME: Implement not
-    fn = create_internal ("octave_jit_++", m_scalar, m_scalar);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *one = llvm::ConstantFP::get (m_scalar_t, 1);
-      llvm::Value *val = fn.argument (m_builder, 0);
-      val = m_builder.CreateFAdd (val, one);
-      fn.do_return (m_builder, val);
-    }
-    m_unary_ops[octave_value::op_incr].add_overload (fn);
-
-    fn = create_internal ("octave_jit_--", m_scalar, m_scalar);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *one = llvm::ConstantFP::get (m_scalar_t, 1);
-      llvm::Value *val = fn.argument (m_builder, 0);
-      val = m_builder.CreateFSub (val, one);
-      fn.do_return (m_builder, val);
-    }
-    m_unary_ops[octave_value::op_decr].add_overload (fn);
-
-    fn = create_internal ("octave_jit_uminus", m_scalar, m_scalar);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *mone = llvm::ConstantFP::get (m_scalar_t, -1);
-      llvm::Value *val = fn.argument (m_builder, 0);
-      val = m_builder.CreateFMul (val, mone);
-      fn.do_return (m_builder, val);
-    }
-    m_unary_ops[octave_value::op_uminus].add_overload (fn);
-
-    fn = create_identity (m_scalar);
-    m_unary_ops[octave_value::op_uplus].add_overload (fn);
-    m_unary_ops[octave_value::op_transpose].add_overload (fn);
-    m_unary_ops[octave_value::op_hermitian].add_overload (fn);
-
-    // now for binary complex operations
-    fn = create_internal ("octave_jit_+_complex_complex", m_complex, m_complex,
-                          m_complex);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *lhs = fn.argument (m_builder, 0);
-      llvm::Value *rhs = fn.argument (m_builder, 1);
-      llvm::Value *real = m_builder.CreateFAdd (complex_real (lhs),
-                                                complex_real (rhs));
-      llvm::Value *imag = m_builder.CreateFAdd (complex_imag (lhs),
-                                                complex_imag (rhs));
-      fn.do_return (m_builder, complex_new (real, imag));
-    }
-    m_binary_ops[octave_value::op_add].add_overload (fn);
-
-    fn = create_internal ("octave_jit_-_complex_complex", m_complex, m_complex,
-                          m_complex);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *lhs = fn.argument (m_builder, 0);
-      llvm::Value *rhs = fn.argument (m_builder, 1);
-      llvm::Value *real = m_builder.CreateFSub (complex_real (lhs),
-                                                complex_real (rhs));
-      llvm::Value *imag = m_builder.CreateFSub (complex_imag (lhs),
-                                                complex_imag (rhs));
-      fn.do_return (m_builder, complex_new (real, imag));
-    }
-    m_binary_ops[octave_value::op_sub].add_overload (fn);
-
-    fn = create_external (JIT_FN (octave_jit_complex_mul),
-                          m_complex, m_complex, m_complex);
-    m_binary_ops[octave_value::op_mul].add_overload (fn);
-    m_binary_ops[octave_value::op_el_mul].add_overload (fn);
-
-    jit_function complex_div = create_external (JIT_FN (octave_jit_complex_div),
-                                                m_complex, m_complex, m_complex);
-    complex_div.mark_can_error ();
-    m_binary_ops[octave_value::op_div].add_overload (fn);
-    m_binary_ops[octave_value::op_ldiv].add_overload (fn);
-
-    fn = create_external (JIT_FN (octave_jit_pow_complex_complex), m_complex,
-                          m_complex, m_complex);
-    m_binary_ops[octave_value::op_pow].add_overload (fn);
-    m_binary_ops[octave_value::op_el_pow].add_overload (fn);
-
-    fn = create_internal ("octave_jit_*_scalar_complex", m_complex, m_scalar,
-                          m_complex);
-    jit_function mul_scalar_complex = fn;
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::BasicBlock *complex_mul = fn.new_block ("complex_mul");
-      llvm::BasicBlock *scalar_mul = fn.new_block ("scalar_mul");
-
-      llvm::Value *fzero = llvm::ConstantFP::get (m_scalar_t, 0);
-      llvm::Value *lhs = fn.argument (m_builder, 0);
-      llvm::Value *rhs = fn.argument (m_builder, 1);
-
-      llvm::Value *cmp = m_builder.CreateFCmpUEQ (complex_imag (rhs), fzero);
-      m_builder.CreateCondBr (cmp, scalar_mul, complex_mul);
-
-      m_builder.SetInsertPoint (scalar_mul);
-      llvm::Value *temp = complex_real (rhs);
-      temp = m_builder.CreateFMul (lhs, temp);
-      fn.do_return (m_builder, complex_new (temp, fzero), false);
-
-      m_builder.SetInsertPoint (complex_mul);
-      temp = complex_new (m_builder.CreateFMul (lhs, complex_real (rhs)),
-                          m_builder.CreateFMul (lhs, complex_imag (rhs)));
-      fn.do_return (m_builder, temp);
-    }
-    m_binary_ops[octave_value::op_mul].add_overload (fn);
-    m_binary_ops[octave_value::op_el_mul].add_overload (fn);
-
-    fn = mirror_binary (mul_scalar_complex);
-    m_binary_ops[octave_value::op_mul].add_overload (fn);
-    m_binary_ops[octave_value::op_el_mul].add_overload (fn);
-
-    fn = create_internal ("octave_jit_+_scalar_complex", m_complex, m_scalar,
-                          m_complex);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *lhs = fn.argument (m_builder, 0);
-      llvm::Value *rhs = fn.argument (m_builder, 1);
-      llvm::Value *real = m_builder.CreateFAdd (lhs, complex_real (rhs));
-      fn.do_return (m_builder, complex_real (rhs, real));
-    }
-    m_binary_ops[octave_value::op_add].add_overload (fn);
-
-    fn = mirror_binary (fn);
-    m_binary_ops[octave_value::op_add].add_overload (fn);
-
-    fn = create_internal ("octave_jit_-_complex_scalar", m_complex, m_complex,
-                          m_scalar);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *lhs = fn.argument (m_builder, 0);
-      llvm::Value *rhs = fn.argument (m_builder, 1);
-      llvm::Value *real = m_builder.CreateFSub (complex_real (lhs), rhs);
-      fn.do_return (m_builder, complex_real (lhs, real));
-    }
-    m_binary_ops[octave_value::op_sub].add_overload (fn);
-
-    fn = create_internal ("octave_jit_-_scalar_complex", m_complex, m_scalar,
-                          m_complex);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *lhs = fn.argument (m_builder, 0);
-      llvm::Value *rhs = fn.argument (m_builder, 1);
-      llvm::Value *real = m_builder.CreateFSub (lhs, complex_real (rhs));
-      fn.do_return (m_builder, complex_real (rhs, real));
-    }
-    m_binary_ops[octave_value::op_sub].add_overload (fn);
-
-    fn = create_external (JIT_FN (octave_jit_pow_scalar_complex), m_complex,
-                          m_scalar, m_complex);
-    m_binary_ops[octave_value::op_pow].add_overload (fn);
-    m_binary_ops[octave_value::op_el_pow].add_overload (fn);
-
-    fn = create_external (JIT_FN (octave_jit_pow_complex_scalar), m_complex,
-                          m_complex, m_scalar);
-    m_binary_ops[octave_value::op_pow].add_overload (fn);
-    m_binary_ops[octave_value::op_el_pow].add_overload (fn);
-
-    // now for binary index operators
-    add_binary_op (m_index, octave_value::op_add, llvm::Instruction::Add);
-
-    // and binary bool operators
-    add_binary_op (m_boolean, octave_value::op_el_or, llvm::Instruction::Or);
-    add_binary_op (m_boolean, octave_value::op_el_and, llvm::Instruction::And);
-
-    // now for printing functions
-    add_print (m_any, reinterpret_cast<void *> (&octave_jit_print_any));
-    add_print (m_scalar, reinterpret_cast<void *> (&octave_jit_print_scalar));
-
-    // initialize for loop
-    fn = create_internal ("octave_jit_for_range_init", m_index, m_range);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *zero = llvm::ConstantInt::get (m_index_t, 0);
-      fn.do_return (m_builder, zero);
-    }
-    m_for_init_fn.add_overload (fn);
-
-    // bounds check for for loop
-    fn = create_internal ("octave_jit_for_range_check", m_boolean, m_range,
-                          m_index);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *nelem
-        = m_builder.CreateExtractValue (fn.argument (m_builder, 0), 3);
-      llvm::Value *idx = fn.argument (m_builder, 1);
-      llvm::Value *ret = m_builder.CreateICmpULT (idx, nelem);
-      fn.do_return (m_builder, ret);
-    }
-    m_for_check_fn.add_overload (fn);
-
-    // index variable for for loop
-    fn = create_internal ("octave_jit_for_range_idx", m_scalar, m_range,
-                          m_index);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *idx = fn.argument (m_builder, 1);
-      llvm::Value *didx = m_builder.CreateSIToFP (idx, m_scalar_t);
-      llvm::Value *rng = fn.argument (m_builder, 0);
-      llvm::Value *base = m_builder.CreateExtractValue (rng, 0);
-      llvm::Value *inc = m_builder.CreateExtractValue (rng, 2);
-
-      llvm::Value *ret = m_builder.CreateFMul (didx, inc);
-      ret = m_builder.CreateFAdd (base, ret);
-      fn.do_return (m_builder, ret);
-    }
-    m_for_index_fn.add_overload (fn);
-
-    // logically true
-    jit_function gripe_nantl
-      = create_external (JIT_FN (octave_jit_err_nan_to_logical_conversion),
-                         nullptr);
-    gripe_nantl.mark_can_error ();
-    fn = create_internal ("octave_jit_logically_true_scalar", m_boolean,
-                          m_scalar);
-    fn.mark_can_error ();
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::BasicBlock *error_block = fn.new_block ("error");
-      llvm::BasicBlock *normal_block = fn.new_block ("normal");
-
-      llvm::Value *check = m_builder.CreateFCmpUNE (fn.argument (m_builder, 0),
-                                                    fn.argument (m_builder, 0));
-      m_builder.CreateCondBr (check, error_block, normal_block);
-
-      m_builder.SetInsertPoint (error_block);
-      gripe_nantl.call (m_builder);
-      m_builder.CreateBr (normal_block);
-      m_builder.SetInsertPoint (normal_block);
-
-      llvm::Value *zero = llvm::ConstantFP::get (m_scalar_t, 0);
-      llvm::Value *ret = m_builder.CreateFCmpONE (fn.argument (m_builder, 0), zero);
-      fn.do_return (m_builder, ret);
-    }
-    m_logically_true_fn.add_overload (fn);
-
-    // logically_true boolean
-    fn = create_identity (m_boolean);
-    m_logically_true_fn.add_overload (fn);
-
-    // make_range
-    // FIXME: May be beneficial to implement all in LLVM
-    jit_function compute_nelem
-      = create_external (JIT_FN (octave_jit_compute_nelem),
-                         m_index, m_scalar, m_scalar, m_scalar);
-    fn = create_internal ("octave_jit_make_range", m_range, m_scalar, m_scalar,
-                          m_scalar);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *base = fn.argument (m_builder, 0);
-      llvm::Value *limit = fn.argument (m_builder, 1);
-      llvm::Value *inc = fn.argument (m_builder, 2);
-      llvm::Value *nelem = compute_nelem.call (m_builder, base, limit, inc);
-
-      llvm::Value *dzero = llvm::ConstantFP::get (m_scalar_t, 0);
-      llvm::Value *izero = llvm::ConstantInt::get (m_index_t, 0);
-      llvm::Value *rng = llvm::ConstantStruct::get (m_range_t, dzero, dzero,
-                                                    dzero, izero, nullptr);
-      rng = m_builder.CreateInsertValue (rng, base, 0);
-      rng = m_builder.CreateInsertValue (rng, limit, 1);
-      rng = m_builder.CreateInsertValue (rng, inc, 2);
-      rng = m_builder.CreateInsertValue (rng, nelem, 3);
-      fn.do_return (m_builder, rng);
-    }
-    m_make_range_fn.add_overload (fn);
-
-    // paren_subsref
-    jit_type *jit_int = do_get_intN (sizeof (int) * 8);
-    llvm::Type *int_t = jit_int->to_llvm ();
-    jit_function ginvalid_index
-      = create_external (JIT_FN (octave_jit_ginvalid_index), nullptr);
-    jit_function gindex_range = create_external (JIT_FN (octave_jit_gindex_range),
-                                                 nullptr, jit_int, jit_int,
-                                                 m_index, m_index);
-
-    fn = create_internal ("()subsref", m_scalar, m_matrix, m_scalar);
-    fn.mark_can_error ();
-
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *one_idx = llvm::ConstantInt::get (m_index_t, 1);
-      llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
-
-      llvm::Value *undef = llvm::UndefValue::get (m_scalar_t);
-      llvm::Value *mat = fn.argument (m_builder, 0);
-      llvm::Value *idx = fn.argument (m_builder, 1);
-
-      // convert index to scalar to integer, and check index >= 1
-      llvm::Value *int_idx = m_builder.CreateFPToSI (idx, m_index_t);
-      llvm::Value *check_idx = m_builder.CreateSIToFP (int_idx, m_scalar_t);
-      llvm::Value *cond0 = m_builder.CreateFCmpUNE (idx, check_idx);
-      llvm::Value *cond1 = m_builder.CreateICmpSLT (int_idx, one_idx);
-      llvm::Value *cond = m_builder.CreateOr (cond0, cond1);
-
-      llvm::BasicBlock *done = fn.new_block ("done");
-      llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
-      llvm::BasicBlock *normal = fn.new_block ("normal", done);
-      m_builder.CreateCondBr (cond, conv_error, normal);
-
-      m_builder.SetInsertPoint (conv_error);
-      ginvalid_index.call (m_builder);
-      m_builder.CreateBr (done);
-
-      m_builder.SetInsertPoint (normal);
-      llvm::Value *len
-        = m_builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (2));
-      cond = m_builder.CreateICmpSGT (int_idx, len);
-
-      llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
-      llvm::BasicBlock *success = fn.new_block ("success", done);
-      m_builder.CreateCondBr (cond, bounds_error, success);
-
-      m_builder.SetInsertPoint (bounds_error);
-      gindex_range.call (m_builder, one_int, one_int, int_idx, len);
-      m_builder.CreateBr (done);
-
-      m_builder.SetInsertPoint (success);
-      llvm::Value *data = m_builder.CreateExtractValue (mat,
-                                                        llvm::ArrayRef<unsigned> (1));
-      llvm::Value *gep = m_builder.CreateInBoundsGEP (data, int_idx);
-      llvm::Value *ret = m_builder.CreateLoad (gep);
-      m_builder.CreateBr (done);
-
-      m_builder.SetInsertPoint (done);
-
-      llvm::PHINode *merge = llvm::PHINode::Create (m_scalar_t, 3);
-      m_builder.Insert (merge);
-      merge->addIncoming (undef, conv_error);
-      merge->addIncoming (undef, bounds_error);
-      merge->addIncoming (ret, success);
-      fn.do_return (m_builder, merge);
-    }
-    paren_subsref_fn.add_overload (fn);
-
-    // paren subsasgn
-    jit_function resize_paren_subsasgn
-      = create_external (JIT_FN (octave_jit_paren_subsasgn_impl), m_matrix,
-                         m_matrix, m_index, m_scalar);
-    fn = create_internal ("octave_jit_paren_subsasgn", m_matrix, m_matrix,
-                          m_scalar, m_scalar);
-    fn.mark_can_error ();
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *one_idx = llvm::ConstantInt::get (m_index_t, 1);
-      llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
-
-      llvm::Value *mat = fn.argument (m_builder, 0);
-      llvm::Value *idx = fn.argument (m_builder, 1);
-      llvm::Value *value = fn.argument (m_builder, 2);
-
-      llvm::Value *int_idx = m_builder.CreateFPToSI (idx, m_index_t);
-      llvm::Value *check_idx = m_builder.CreateSIToFP (int_idx, m_scalar_t);
-      llvm::Value *cond0 = m_builder.CreateFCmpUNE (idx, check_idx);
-      llvm::Value *cond1 = m_builder.CreateICmpSLT (int_idx, one_idx);
-      llvm::Value *cond = m_builder.CreateOr (cond0, cond1);
-
-      llvm::BasicBlock *done = fn.new_block ("done");
-
-      llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
-      llvm::BasicBlock *normal = fn.new_block ("normal", done);
-      m_builder.CreateCondBr (cond, conv_error, normal);
-      m_builder.SetInsertPoint (conv_error);
-      ginvalid_index.call (m_builder);
-      m_builder.CreateBr (done);
-
-      m_builder.SetInsertPoint (normal);
-      llvm::Value *len = m_builder.CreateExtractValue (mat, 2);
-      cond0 = m_builder.CreateICmpSGT (int_idx, len);
-
-      llvm::Value *rcount = m_builder.CreateExtractValue (mat, 0);
-      rcount = m_builder.CreateLoad (rcount);
-      cond1 = m_builder.CreateICmpSGT (rcount, one_int);
-      cond = m_builder.CreateOr (cond0, cond1);
-
-      llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
-      llvm::BasicBlock *success = fn.new_block ("success", done);
-      m_builder.CreateCondBr (cond, bounds_error, success);
-
-      // resize on out of bounds access
-      m_builder.SetInsertPoint (bounds_error);
-      llvm::Value *resize_result = resize_paren_subsasgn.call (m_builder, mat,
-                                                               int_idx, value);
-      m_builder.CreateBr (done);
-
-      m_builder.SetInsertPoint (success);
-      llvm::Value *data
-        = m_builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (1));
-      llvm::Value *gep = m_builder.CreateInBoundsGEP (data, int_idx);
-      m_builder.CreateStore (value, gep);
-      m_builder.CreateBr (done);
-
-      m_builder.SetInsertPoint (done);
-
-      llvm::PHINode *merge = llvm::PHINode::Create (m_matrix_t, 3);
-      m_builder.Insert (merge);
-      merge->addIncoming (mat, conv_error);
-      merge->addIncoming (resize_result, bounds_error);
-      merge->addIncoming (mat, success);
-      fn.do_return (m_builder, merge);
-    }
-    paren_subsasgn_fn.add_overload (fn);
-
-    fn = create_external (JIT_FN (octave_jit_paren_subsasgn_matrix_range),
-                          m_matrix, m_matrix, m_range, m_scalar);
-    fn.mark_can_error ();
-    paren_subsasgn_fn.add_overload (fn);
-
-    fn = create_internal ("octave_jit_end1_matrix", m_scalar, m_matrix,
-                          m_index, m_index);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *mat = fn.argument (m_builder, 0);
-      llvm::Value *ret = m_builder.CreateExtractValue (mat, 2);
-      fn.do_return (m_builder, m_builder.CreateSIToFP (ret, m_scalar_t));
-    }
-    m_end1_fn.add_overload (fn);
-
-    fn = create_external (JIT_FN (octave_jit_end_matrix),m_scalar, m_matrix,
-                          m_index, m_index);
-    m_end_fn.add_overload (fn);
-
-    // -------------------- create_undef --------------------
-    fn = create_external (JIT_FN (octave_jit_create_undef), m_any);
-    m_create_undef_fn.add_overload (fn);
-
-    m_casts[m_any->type_id ()].stash_name ("(any)");
-    m_casts[m_scalar->type_id ()].stash_name ("(scalar)");
-    m_casts[m_complex->type_id ()].stash_name ("(complex)");
-    m_casts[m_matrix->type_id ()].stash_name ("(matrix)");
-    m_casts[m_range->type_id ()].stash_name ("(range)");
-
-    // cast m_any <- matrix
-    fn = create_external (JIT_FN (octave_jit_cast_any_matrix), m_any,
-                          m_matrix);
-    m_casts[m_any->type_id ()].add_overload (fn);
-
-    // cast matrix <- any
-    fn = create_external (JIT_FN (octave_jit_cast_matrix_any), m_matrix,
-                          m_any);
-    m_casts[m_matrix->type_id ()].add_overload (fn);
-
-    // cast any <- range
-    fn = create_external (JIT_FN (octave_jit_cast_any_range), m_any, m_range);
-    m_casts[m_any->type_id ()].add_overload (fn);
-
-    // cast range <- any
-    fn = create_external (JIT_FN (octave_jit_cast_range_any), m_range, m_any);
-    m_casts[m_range->type_id ()].add_overload (fn);
-
-    // cast any <- scalar
-    fn = create_external (JIT_FN (octave_jit_cast_any_scalar), m_any,
-                          m_scalar);
-    m_casts[m_any->type_id ()].add_overload (fn);
-
-    // cast scalar <- any
-    fn = create_external (JIT_FN (octave_jit_cast_scalar_any), m_scalar,
-                          m_any);
-    m_casts[m_scalar->type_id ()].add_overload (fn);
-
-    // cast any <- complex
-    fn = create_external (JIT_FN (octave_jit_cast_any_complex), m_any,
-                          m_complex);
-    m_casts[m_any->type_id ()].add_overload (fn);
-
-    // cast complex <- any
-    fn = create_external (JIT_FN (octave_jit_cast_complex_any), m_complex,
-                          m_any);
-    m_casts[m_complex->type_id ()].add_overload (fn);
-
-    // cast complex <- scalar
-    fn = create_internal ("octave_jit_cast_complex_scalar", m_complex,
-                          m_scalar);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    {
-      llvm::Value *zero = llvm::ConstantFP::get (m_scalar_t, 0);
-      fn.do_return (m_builder, complex_new (fn.argument (m_builder, 0), zero));
-    }
-    m_casts[m_complex->type_id ()].add_overload (fn);
-
-    // cast scalar <- complex
-    fn = create_internal ("octave_jit_cast_scalar_complex", m_scalar,
-                          m_complex);
-    body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-    fn.do_return (m_builder, complex_real (fn.argument (m_builder, 0)));
-    m_casts[m_scalar->type_id ()].add_overload (fn);
-
-    // cast any <- any
-    fn = create_identity (m_any);
-    m_casts[m_any->type_id ()].add_overload (fn);
-
-    // cast scalar <- scalar
-    fn = create_identity (m_scalar);
-    m_casts[m_scalar->type_id ()].add_overload (fn);
-
-    // cast complex <- complex
-    fn = create_identity (m_complex);
-    m_casts[m_complex->type_id ()].add_overload (fn);
-
-    // -------------------- builtin functions --------------------
-    add_builtin ("#unknown_function");
-    m_unknown_function = m_builtins["#unknown_function"];
-
-    add_builtin ("sin");
-    register_intrinsic ("sin", llvm::Intrinsic::sin, m_scalar, m_scalar);
-    register_generic ("sin", m_matrix, m_matrix);
-
-    add_builtin ("cos");
-    register_intrinsic ("cos", llvm::Intrinsic::cos, m_scalar, m_scalar);
-    register_generic ("cos", m_matrix, m_matrix);
-
-    add_builtin ("exp");
-    register_intrinsic ("exp", llvm::Intrinsic::exp, m_scalar, m_scalar);
-    register_generic ("exp", m_matrix, m_matrix);
-
-    add_builtin ("balance");
-    register_generic ("balance", m_matrix, m_matrix);
-
-    add_builtin ("cond");
-    register_generic ("cond", m_scalar, m_matrix);
-
-    add_builtin ("det");
-    register_generic ("det", m_scalar, m_matrix);
-
-    add_builtin ("norm");
-    register_generic ("norm", m_scalar, m_matrix);
-
-    add_builtin ("rand");
-    register_generic ("rand", m_matrix, m_scalar);
-    register_generic ("rand", m_matrix, std::vector<jit_type *> (2, m_scalar));
-
-    add_builtin ("magic");
-    register_generic ("magic", m_matrix, m_scalar);
-    register_generic ("magic", m_matrix,
-                      std::vector<jit_type *> (2, m_scalar));
-
-    add_builtin ("eye");
-    register_generic ("eye", m_matrix, m_scalar);
-    register_generic ("eye", m_matrix, std::vector<jit_type *> (2, m_scalar));
-
-    add_builtin ("mod");
-    register_generic ("mod", m_scalar, std::vector<jit_type *> (2, m_scalar));
-
-    // m_casts.resize (m_next_id + 1);
-    jit_function any_id = create_identity (m_any);
-    jit_function grab_any = create_external (JIT_FN (octave_jit_grab_any),
-                                             m_any, m_any);
-
-    jit_function release_any = m_release_fn.overload (m_any);
-
-    std::vector<jit_type *> args;
-    args.resize (1);
-
-    for (auto iter = m_builtins.begin ();
-         iter != m_builtins.end (); ++iter)
-      {
-        jit_type *btype = iter->second;
-        args[0] = btype;
-
-        m_grab_fn.add_overload (jit_function (grab_any, btype, args));
-        m_release_fn.add_overload (jit_function (release_any, 0, args));
-        m_casts[m_any->type_id ()].add_overload (jit_function (any_id, m_any,
-                                                               args));
-
-        args[0] = m_any;
-        m_casts[btype->type_id ()].add_overload (jit_function (any_id, btype,
-                                                               args));
-      }
-
-    m_base_jit_module->finalizeObject ();
-
-    s_in_construction = false;
-  }
-
-  // create a function with an external calling convention
-  // forces the function pointer to be specified
-  template <typename fn_ptr_type> jit_function
-  jit_typeinfo::create_external (fn_ptr_type fn,
-                                 const llvm::Twine& name,
-                                 jit_type *ret,
-                                 const std::vector<jit_type *>& args) const
-  {
-    jit_function retval (m_base_jit_module, jit_convention::external,
-                         name, ret, args);
-
-    m_base_jit_module->add_global_mapping (retval.to_llvm (), fn);
-
-    return retval;
-  }
-
-  jit_type*
-  jit_typeinfo::do_register_new_type (const std::string& name,
-                                      jit_type *parent,
-                                      llvm::Type *llvm_type,
-                                      bool skip_paren)
-  {
-    // FIXME: Currently our types do *not* form a lattice
-    assert ((name == "any") || (name == "any_ptr")
-            || (name == "scalar_ptr") || (parent != nullptr));
-
-    jit_type *ret = new jit_type (name, parent, llvm_type, skip_paren,
-                                  m_next_id++);
-    m_id_to_type.push_back (ret);
-
-    m_casts.push_back (jit_operation ("(" + name + ")"));
-    m_identities.push_back (jit_function ());
-
-    return ret;
-  }
-
-  jit_type*
-  jit_typeinfo::do_get_intN (std::size_t nbits) const
-  {
-    std::map<std::size_t, jit_type *>::const_iterator iter = m_ints.find (nbits);
-    if (iter != m_ints.end ())
-      return iter->second;
-
-    throw jit_fail_exception ("No such integer type");
-  }
-
-  const jit_function&
-  jit_typeinfo::do_end (jit_value *value, jit_value *idx, jit_value *count)
-  {
-    jit_const_index *ccount = dynamic_cast<jit_const_index *> (count);
-    if (ccount && ccount->value () == 1)
-      return m_end1_fn.overload (value->type (), idx->type (), count->type ());
-
-    return m_end_fn.overload (value->type (), idx->type (), count->type ());
-  }
-
-  void
-  jit_typeinfo::add_print (jit_type *ty, void *fptr)
-  {
-    std::stringstream name;
-    name << "octave_jit_print_" << ty->name ();
-
-    jit_function fn = create_external (fptr, name.str (), nullptr,
-                                       do_get_intN (8), ty);
-
-    m_print_fn.add_overload (fn);
-  }
-
-  // FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp
-  void
-  jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op)
-  {
-    std::stringstream fname;
-    octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
-    fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op)
-          << '_' << ty->name ();
-
-    jit_function fn = create_internal (fname.str (), ty, ty, ty);
-    llvm::BasicBlock *block = fn.new_block ();
-    m_builder.SetInsertPoint (block);
-    llvm::Instruction::BinaryOps temp
-      = static_cast<llvm::Instruction::BinaryOps>(llvm_op);
-
-    llvm::Value *ret = m_builder.CreateBinOp (temp, fn.argument (m_builder, 0),
-                                              fn.argument (m_builder, 1));
-    fn.do_return (m_builder, ret);
-    m_binary_ops[op].add_overload (fn);
-  }
-
-  void
-  jit_typeinfo::add_binary_icmp (jit_type *ty, int op, int llvm_op)
-  {
-    std::stringstream fname;
-    octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
-    fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
-          << '_' << ty->name ();
-
-    jit_function fn = create_internal (fname.str (), m_boolean, ty, ty);
-    llvm::BasicBlock *block = fn.new_block ();
-    m_builder.SetInsertPoint (block);
-    llvm::CmpInst::Predicate temp
-      = static_cast<llvm::CmpInst::Predicate>(llvm_op);
-    llvm::Value *ret = m_builder.CreateICmp (temp, fn.argument (m_builder, 0),
-                                             fn.argument (m_builder, 1));
-    fn.do_return (m_builder, ret);
-    m_binary_ops[op].add_overload (fn);
-  }
-
-  void
-  jit_typeinfo::add_binary_fcmp (jit_type *ty, int op, int llvm_op)
-  {
-    std::stringstream fname;
-    octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
-    fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
-          << '_' << ty->name ();
-
-    jit_function fn = create_internal (fname.str (), m_boolean, ty, ty);
-    llvm::BasicBlock *block = fn.new_block ();
-    m_builder.SetInsertPoint (block);
-    llvm::CmpInst::Predicate temp
-      = static_cast<llvm::CmpInst::Predicate>(llvm_op);
-    llvm::Value *ret = m_builder.CreateFCmp (temp, fn.argument (m_builder, 0),
-                                             fn.argument (m_builder, 1));
-    fn.do_return (m_builder, ret);
-    m_binary_ops[op].add_overload (fn);
-  }
-
-  jit_function
-  jit_typeinfo::create_identity (jit_type *type)
-  {
-    std::size_t id = type->type_id ();
-    if (id >= m_identities.size ())
-      m_identities.resize (id + 1);
-
-    if (! m_identities[id].valid ())
-      {
-        std::stringstream name;
-        name << "id_" << type->name ();
-
-        jit_function fn = create_internal (name.str (), type, type);
-        llvm::BasicBlock *body = fn.new_block ();
-        m_builder.SetInsertPoint (body);
-        fn.do_return (m_builder, fn.argument (m_builder, 0));
-        return m_identities[id] = fn;
-      }
-
-    return m_identities[id];
-  }
-
-  llvm::Value *
-  jit_typeinfo::do_insert_error_check (llvm::IRBuilderD& abuilder)
-  {
-    return abuilder.CreateLoad (m_lerror_state);
-  }
-
-  llvm::Value *
-  jit_typeinfo::do_insert_interrupt_check (llvm::IRBuilderD& abuilder)
-  {
-    llvm::LoadInst *val = abuilder.CreateLoad (m_loctave_interrupt_state);
-    val->setVolatile (true);
-    return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0));
-  }
-
-  void
-  jit_typeinfo::add_builtin (const std::string& name)
-  {
-    jit_type *btype = do_register_new_type (name, m_any, m_any_t, true);
-    m_builtins[name] = btype;
-
-    octave_builtin *ov_builtin = find_builtin (name);
-    if (ov_builtin)
-      ov_builtin->stash_jit (*btype);
-  }
-
-  void
-  jit_typeinfo::register_intrinsic (const std::string& name, std::size_t iid,
-                                    jit_type *result,
-                                    const std::vector<jit_type *>& args)
-  {
-    jit_type *builtin_type = m_builtins[name];
-    std::size_t nargs = args.size ();
-    std::vector<llvm::Type*> llvm_args (nargs);
-    for (std::size_t i = 0; i < nargs; ++i)
-      llvm_args[i] = args[i]->to_llvm ();
-
-    llvm::Function *ifun = m_base_jit_module->
-      get_intrinsic_declaration (iid, llvm_args);
-
-    std::stringstream fn_name;
-    fn_name << "octave_jit_" << name;
-
-    std::vector<jit_type *> args1 (nargs + 1);
-    args1[0] = builtin_type;
-    std::copy (args.begin (), args.end (), args1.begin () + 1);
-
-    // The first argument will be the Octave function, but we already know that
-    // the function call is the equivalent of the intrinsic, so we ignore it
-    // and call the intrinsic with the remaining arguments.
-    jit_function fn = create_internal (fn_name.str (), result, args1);
-    llvm::BasicBlock *body = fn.new_block ();
-    m_builder.SetInsertPoint (body);
-
-    llvm::SmallVector<llvm::Value *, 5> fargs (nargs);
-    for (std::size_t i = 0; i < nargs; ++i)
-      fargs[i] = fn.argument (m_builder, i + 1);
-
-    llvm::Value *ret = m_builder.CreateCall (ifun, fargs);
-    fn.do_return (m_builder, ret);
-    paren_subsref_fn.add_overload (fn);
-  }
-
-  octave_builtin *
-  jit_typeinfo::find_builtin (const std::string& name)
-  {
-    symbol_table& symtab = __get_symbol_table__ ("jit_typeinfo::find_builtin");
-
-    // FIXME: Finalize what we want to store in octave_builtin, then add
-    // functions to access these values in octave_value
-    octave_value ov_builtin = symtab.builtin_find (name);
-    return dynamic_cast<octave_builtin *> (ov_builtin.internal_rep ());
-  }
-
-  void
-  jit_typeinfo::register_generic (const std::string& name, jit_type *result,
-                                  const std::vector<jit_type *>& args)
-  {
-    octave_builtin *builtin = find_builtin (name);
-    if (! builtin)
-      return;
-
-    std::vector<jit_type *> fn_args (args.size () + 1);
-    fn_args[0] = m_builtins[name];
-    std::copy (args.begin (), args.end (), fn_args.begin () + 1);
-    jit_function fn = create_internal (name, result, fn_args);
-    fn.mark_can_error ();
-    llvm::BasicBlock *block = fn.new_block ();
-    m_builder.SetInsertPoint (block);
-    llvm::ArrayType *array_t = llvm::ArrayType::get (m_any_t, args.size ());
-    llvm::Value *array = llvm::UndefValue::get (array_t);
-    for (std::size_t i = 0; i < args.size (); ++i)
-      {
-        llvm::Value *arg = fn.argument (m_builder, i + 1);
-        jit_function agrab = m_grab_fn.overload (args[i]);
-        if (agrab.valid ())
-          arg = agrab.call (m_builder, arg);
-        jit_function acast = do_cast (m_any, args[i]);
-        array = m_builder.CreateInsertValue (array,
-                                             acast.call (m_builder, arg), i);
-      }
-
-    llvm::Value *array_mem = m_builder.CreateAlloca (array_t);
-    m_builder.CreateStore (array, array_mem);
-    array = m_builder.CreateBitCast (array_mem, m_any_t->getPointerTo ());
-
-    jit_type *jintTy = do_get_intN (sizeof (octave_builtin::fcn) * 8);
-    llvm::Type *intTy = jintTy->to_llvm ();
-    std::size_t fcn_int = reinterpret_cast<std::size_t> (builtin->function ());
-    llvm::Value *fcn = llvm::ConstantInt::get (intTy, fcn_int);
-    llvm::Value *nargin = llvm::ConstantInt::get (intTy, args.size ());
-    std::size_t result_int = reinterpret_cast<std::size_t> (result);
-    llvm::Value *res_llvm = llvm::ConstantInt::get (intTy, result_int);
-    llvm::Value *ret = m_any_call.call (m_builder, fcn, nargin, array,
-                                        res_llvm);
-
-    jit_function cast_result = do_cast (result, m_any);
-    fn.do_return (m_builder, cast_result.call (m_builder, ret));
-    paren_subsref_fn.add_overload (fn);
-  }
-
-  jit_function
-  jit_typeinfo::mirror_binary (const jit_function& fn)
-  {
-    jit_function ret = create_internal (fn.name () + "_reverse",
-                                        fn.result (), fn.argument_type (1),
-                                        fn.argument_type (0));
-    if (fn.can_error ())
-      ret.mark_can_error ();
-
-    llvm::BasicBlock *body = ret.new_block ();
-    m_builder.SetInsertPoint (body);
-    llvm::Value *result = fn.call (m_builder, ret.argument (m_builder, 1),
-                                   ret.argument (m_builder, 0));
-    if (ret.result ())
-      ret.do_return (m_builder, result);
-    else
-      ret.do_return (m_builder);
-
-    return ret;
-  }
-
-  llvm::Value *
-  jit_typeinfo::do_pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) const
-  {
-    llvm::Value *real = bld.CreateExtractValue (cplx, 0);
-    llvm::Value *imag = bld.CreateExtractValue (cplx, 1);
-    llvm::Value *ret = llvm::UndefValue::get (m_complex_ret);
-
-    unsigned int re_idx[] = {0, 0};
-    unsigned int im_idx[] = {0, 1};
-    ret = bld.CreateInsertValue (ret, real, re_idx);
-    return bld.CreateInsertValue (ret, imag, im_idx);
-  }
-
-  llvm::Value *
-  jit_typeinfo::unpack_complex (llvm::IRBuilderD& bld, llvm::Value *result)
-  {
-    unsigned int re_idx[] = {0, 0};
-    unsigned int im_idx[] = {0, 1};
-
-    llvm::Type *m_complex_t = get_complex ()->to_llvm ();
-    llvm::Value *real = bld.CreateExtractValue (result, re_idx);
-    llvm::Value *imag = bld.CreateExtractValue (result, im_idx);
-    llvm::Value *ret = llvm::UndefValue::get (m_complex_t);
-
-    ret = bld.CreateInsertValue (ret, real, 0);
-    return bld.CreateInsertValue (ret, imag, 1);
-  }
-
-  llvm::Value *
-  jit_typeinfo::complex_real (llvm::Value *cx)
-  {
-    return m_builder.CreateExtractValue (cx, 0);
-  }
-
-  llvm::Value *
-  jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real)
-  {
-    return m_builder.CreateInsertValue (cx, real, 0);
-  }
-
-  llvm::Value *
-  jit_typeinfo::complex_imag (llvm::Value *cx)
-  {
-    return m_builder.CreateExtractValue (cx, 1);
-  }
-
-  llvm::Value *
-  jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag)
-  {
-    return m_builder.CreateInsertValue (cx, imag, 1);
-  }
-
-  llvm::Value *
-  jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag)
-  {
-    llvm::Value *ret = llvm::UndefValue::get (m_complex->to_llvm ());
-    ret = complex_real (ret, real);
-    return complex_imag (ret, imag);
-  }
-
-  jit_type *
-  jit_typeinfo::do_type_of (const octave_value& ov) const
-  {
-    if (ov.is_function ())
-      {
-        // FIXME: This is ugly, we need to finalize how we want to do this,
-        // then have octave_value fully support the needed functionality
-        octave_builtin *builtin
-          = dynamic_cast<octave_builtin *> (ov.internal_rep ());
-        return builtin && builtin->to_jit () ? builtin->to_jit ()
-                                             : m_unknown_function;
-      }
-
-    if (ov.is_range ())
-      return m_range;
-
-    if (ov.is_double_type () && ! ov.iscomplex ())
-      {
-        if (ov.is_real_scalar ())
-          return m_scalar;
-
-        if (ov.is_matrix_type ())
-          return m_matrix;
-      }
-
-    if (ov.is_complex_scalar ())
-      {
-        Complex cv = ov.complex_value ();
-
-        // We don't really represent complex values, instead we represent
-        // complex_or_scalar.  If the imag value is zero, we assume a scalar.
-        if (cv.imag () != 0)
-          return m_complex;
-      }
-
-    return m_any;
-  }
-}
-
-#endif
--- a/libinterp/parse-tree/jit-typeinfo.h	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,941 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-#if ! defined (octave_jit_typeinfo_h)
-#define octave_jit_typeinfo_h 1
-
-#include "octave-config.h"
-
-#if defined (HAVE_LLVM)
-
-#include <map>
-#include <vector>
-
-#include "Range.h"
-#include "jit-util.h"
-
-namespace octave
-{
-  class jit_typeinfo;
-  class jit_module;
-
-  // Defines the type system used by jit and a singleton class, jit_typeinfo, to
-  // manage the types.
-  //
-  // FIXME:
-  // Operations are defined and implemented in jit_typeinfo.  Eventually they
-  // should be moved elsewhere. (just like with octave_typeinfo)
-
-  // jit_range is compatible with the llvm range structure
-  struct
-  jit_range
-  {
-    jit_range (const range<double>& from)
-      : m_base (from.base ()), m_limit (from.limit ()), m_inc (from.inc ()),
-        m_nelem (from.numel ())
-    { }
-
-    operator range<double> () const
-    {
-      return range<double> (m_base, m_inc, m_limit);
-    }
-
-    bool all_elements_are_ints (void) const;
-
-    double m_base;
-    double m_limit;
-    double m_inc;
-    octave_idx_type m_nelem;
-  };
-
-  std::ostream& operator << (std::ostream& os, const jit_range& rng);
-
-  // jit_array is compatible with the llvm array/matrix structures
-  template <typename T, typename U>
-  struct
-  jit_array
-  {
-    jit_array (void) : m_array (0) { }
-
-    jit_array (T& from) : m_array (new T (from))
-    {
-      update ();
-    }
-
-    void update (void)
-    {
-      m_ref_count = m_array->jit_ref_count ();
-      m_slice_data = m_array->jit_slice_data () - 1;
-      m_slice_len = m_array->numel ();
-      m_ndims = m_array->ndims ();
-      m_dimensions = m_array->jit_dimensions ();
-    }
-
-    void update (T *aarray)
-    {
-      m_array = aarray;
-      update ();
-    }
-
-    operator T () const
-    {
-      return *m_array;
-    }
-
-    int m_ref_count;
-
-    U *m_slice_data;
-    octave_idx_type m_slice_len;
-    octave_idx_type m_ndims;
-    octave_idx_type *m_dimensions;
-
-    T *m_array;
-  };
-
-  typedef jit_array<NDArray, double> jit_matrix;
-
-  std::ostream& operator << (std::ostream& os, const jit_matrix& mat);
-
-  // calling convention
-  namespace jit_convention
-  {
-    enum
-    type
-    {
-      // internal to jit
-      internal,
-
-      // an external C call
-      external,
-
-      length
-    };
-  }
-
-  // Used to keep track of estimated (infered) types during JIT.  This is a
-  // hierarchical type system which includes both concrete and abstract types.
-  //
-  // The types form a lattice.  Currently we only allow for one parent type, but
-  // eventually we may allow for multiple predecessors.
-  class
-  jit_type
-  {
-  public:
-
-    typedef llvm::Value *(*convert_fn) (llvm::IRBuilderD&, llvm::Value *);
-
-    jit_type (const std::string& aname, jit_type *aparent, llvm::Type *allvm_type,
-              bool askip_paren, int aid);
-
-    // a user readable type name
-    const std::string& name (void) const { return m_name; }
-
-    // a unique id for the type
-    int type_id (void) const { return m_id; }
-
-    // An abstract base type, may be null
-    jit_type * parent (void) const { return m_parent; }
-
-    // convert to an llvm type
-    llvm::Type * to_llvm (void) const { return m_llvm_type; }
-
-    // how this type gets passed as a function argument
-    llvm::Type * to_llvm_arg (void) const;
-
-    std::size_t depth (void) const { return m_depth; }
-
-    bool skip_paren (void) const { return m_skip_paren; }
-
-    // -------------------- Calling Convention information --------------------
-
-    // A function declared like: mytype foo (int arg0, int arg1);
-    // Will be converted to: void foo (mytype *retval, int arg0, int arg1)
-    // if mytype is sret.  The caller is responsible for allocating space for
-    // retval. (on the stack)
-    bool sret (jit_convention::type cc) const { return m_sret[cc]; }
-
-    void mark_sret (jit_convention::type cc)
-    { m_sret[cc] = true; }
-
-    // A function like: void foo (mytype arg0)
-    // Will be converted to: void foo (mytype *arg0)
-    // Basically just pass by reference.
-    bool pointer_arg (jit_convention::type cc) const { return m_pointer_arg[cc]; }
-
-    void mark_pointer_arg (jit_convention::type cc)
-    { m_pointer_arg[cc] = true; }
-
-    // Convert into an equivalent form before calling.  For example, complex is
-    // represented as two values llvm vector, but we need to pass it as a two
-    // valued llvm structure to C functions.
-    convert_fn pack (jit_convention::type cc) { return m_pack[cc]; }
-
-    void set_pack (jit_convention::type cc, convert_fn fn) { m_pack[cc] = fn; }
-
-    // The inverse operation of pack.
-    convert_fn unpack (jit_convention::type cc) { return m_unpack[cc]; }
-
-    void set_unpack (jit_convention::type cc, convert_fn fn)
-    { m_unpack[cc] = fn; }
-
-    // The resulting type after pack is called.
-    llvm::Type * packed_type (jit_convention::type cc)
-    { return m_packed_type[cc]; }
-
-    void set_packed_type (jit_convention::type cc, llvm::Type *ty)
-    { m_packed_type[cc] = ty; }
-
-  private:
-
-    std::string m_name;
-    jit_type *m_parent;
-    llvm::Type *m_llvm_type;
-    int m_id;
-    std::size_t m_depth;
-    bool m_skip_paren;
-
-    bool m_sret[jit_convention::length];
-    bool m_pointer_arg[jit_convention::length];
-
-    convert_fn m_pack[jit_convention::length];
-    convert_fn m_unpack[jit_convention::length];
-
-    llvm::Type *m_packed_type[jit_convention::length];
-  };
-
-  // separate print function to allow easy printing if type is null
-  std::ostream& jit_print (std::ostream& os, jit_type *atype);
-
-  // Find common type
-  jit_type* jit_type_join (jit_type *lhs, jit_type *rhs);
-
-
-
-  class jit_value;
-
-  // An abstraction for calling llvm functions with jit_values.  Deals with
-  // calling convention details.
-  class
-  jit_function
-  {
-    friend std::ostream& operator << (std::ostream& os, const jit_function& fn);
-
-  public:
-
-    // create a function in an invalid state
-    jit_function (void);
-
-    jit_function (const jit_module *amodule, jit_convention::type acall_conv,
-                  const llvm::Twine& aname, jit_type *aresult,
-                  const std::vector<jit_type *>& aargs);
-
-    // Use an existing function, but change the argument types.  The new argument
-    // types must behave the same for the current calling convention.
-    jit_function (const jit_function& fn, jit_type *aresult,
-                  const std::vector<jit_type *>& aargs);
-
-    jit_function (const jit_function& fn);
-
-    // erase the internal LLVM function (if it exists).  Will become invalid.
-    void erase (void);
-
-    bool valid (void) const { return m_llvm_function; }
-
-    std::string name (void) const;
-
-    llvm::BasicBlock * new_block (const std::string& aname = "body",
-                                  llvm::BasicBlock *insert_before = nullptr);
-
-    typedef std::vector<llvm::Value *> arg_vec;
-
-    llvm::Value * call (llvm::IRBuilderD& builder,
-                        const arg_vec& in_args = arg_vec ()) const;
-
-    llvm::Value * call (llvm::IRBuilderD& builder,
-                        const std::vector<jit_value *>& in_args) const;
-
-    template <typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, arg_vec& in_args,
-                        llvm::Value * arg1, Args... other_args) const
-    {
-      in_args.push_back (arg1);
-      return call (builder, in_args, other_args...);
-    }
-
-    template <typename T, typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, arg_vec& in_args,
-                        T * arg1, Args... other_args) const
-    {
-      in_args.push_back (arg1->to_llvm ());
-      return call (builder, in_args, other_args...);
-    }
-
-    template <typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, llvm::Value * arg1,
-                        Args... other_args) const
-    {
-      arg_vec in_args;
-      in_args.reserve (1 + sizeof... (other_args));
-      in_args.push_back (arg1);
-      return call (builder, in_args, other_args...);
-    }
-
-    template <typename T, typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, T * arg1,
-                        Args... other_args) const
-    {
-      arg_vec in_args;
-      in_args.reserve (1 + sizeof... (other_args));
-      in_args.push_back (arg1->to_llvm ());
-      return call (builder, in_args, other_args...);
-    }
-
-    llvm::Value * argument (llvm::IRBuilderD& builder, std::size_t idx) const;
-
-    void do_return (llvm::IRBuilderD& builder, llvm::Value *rval = nullptr,
-                    bool verify = true);
-
-    llvm::Function * to_llvm (void) const { return m_llvm_function; }
-
-    // If true, then the return value is passed as a pointer in the first argument
-    bool sret (void) const { return m_result && m_result->sret (m_call_conv); }
-
-    bool can_error (void) const { return m_can_error; }
-
-    void mark_can_error (void) { m_can_error = true; }
-
-    jit_type * result (void) const { return m_result; }
-
-    jit_type * argument_type (std::size_t idx) const
-    {
-      assert (idx < m_args.size ());
-      return m_args[idx];
-    }
-
-    const std::vector<jit_type *>& arguments (void) const { return m_args; }
-
-  private:
-
-    const jit_module *m_module;
-    llvm::Function *m_llvm_function;
-    jit_type *m_result;
-    std::vector<jit_type *> m_args;
-    jit_convention::type m_call_conv;
-    bool m_can_error;
-  };
-
-  std::ostream& operator << (std::ostream& os, const jit_function& fn);
-
-  // Keeps track of information about how to implement operations (+, -,
-  // *, etc.) and their resulting types.
-  class
-  jit_operation
-  {
-  public:
-
-    jit_operation (const std::string& aname)  { m_name = aname; }
-
-    // type signature vector
-    typedef std::vector<jit_type *> signature_vec;
-
-    virtual ~jit_operation (void);
-
-    void add_overload (const jit_function& func)
-    {
-      add_overload (func, func.arguments ());
-    }
-
-    void add_overload (const jit_function& func,
-                       const signature_vec& args);
-
-    const jit_function& overload (const signature_vec& types) const;
-
-    template <typename ...Args>
-    const jit_function& overload (signature_vec& args, jit_type * arg1,
-                                  Args... other_args) const
-    {
-      args.push_back (arg1);
-      return overload (args, other_args...);
-    }
-
-    template <typename ...Args>
-    const jit_function& overload (jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return overload (args, other_args...);
-    }
-
-    jit_type * result (const signature_vec& types) const
-    {
-      const jit_function& temp = overload (types);
-      return temp.result ();
-    }
-
-    template <typename ...Args>
-    jit_type * result (signature_vec& args, jit_type * arg1,
-                       Args... other_args) const
-    {
-      args.push_back (arg1);
-      return overload (args, other_args...);
-    }
-
-    template <typename ...Args>
-    jit_type * result (jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return overload (args, other_args...);
-    }
-
-    const std::string& name (void) const { return m_name; }
-
-    void stash_name (const std::string& aname) { m_name = aname; }
-
-  protected:
-
-    virtual jit_function * generate (const signature_vec& types) const;
-
-  private:
-
-    Array<octave_idx_type> to_idx (const signature_vec& types) const;
-
-    const jit_function& do_generate (const signature_vec& types) const;
-
-    struct signature_cmp
-    {
-      bool operator () (const signature_vec *lhs, const signature_vec *rhs) const;
-    };
-
-    typedef std::map<const signature_vec *, jit_function *, signature_cmp>
-      generated_map;
-
-    mutable generated_map m_generated;
-
-    std::vector<Array<jit_function>> m_overloads;
-
-    std::string m_name;
-  };
-
-
-  class
-  jit_index_operation : public jit_operation
-  {
-  public:
-
-    jit_index_operation (const jit_typeinfo& ti, const std::string& name)
-      : jit_operation (name), m_typeinfo (ti) { }
-
-  protected:
-
-    virtual jit_function * generate (const signature_vec& types) const;
-
-    virtual jit_function * generate_matrix (const signature_vec& types) const = 0;
-
-    // helper functions
-    // [start_idx, end_idx).
-    llvm::Value * create_arg_array (llvm::IRBuilderD& builder,
-                                    const jit_function& fn, std::size_t start_idx,
-                                    std::size_t end_idx) const;
-
-    const jit_typeinfo& m_typeinfo;
-  };
-
-  class
-  jit_paren_subsref : public jit_index_operation
-  {
-  public:
-
-    // FIXME: Avoid creating object in an invalid state?
-    jit_paren_subsref (const jit_typeinfo& ti);
-    ~jit_paren_subsref (void);
-    void init_paren_scalar (void);
-
-  protected:
-
-    virtual jit_function * generate_matrix (const signature_vec& types) const;
-
-  private:
-
-    jit_function *m_paren_scalar;
-  };
-
-  class
-  jit_paren_subsasgn : public jit_index_operation
-  {
-  public:
-
-    // FIXME: Avoid creating object in an invalid state?
-    jit_paren_subsasgn (const jit_typeinfo& ti);
-    ~jit_paren_subsasgn (void);
-    void init_paren_scalar (void);
-
-  protected:
-
-    jit_function * generate_matrix (const signature_vec& types) const;
-
-  private:
-
-    jit_function *m_paren_scalar;
-  };
-
-
-  // A singleton class which handles the construction of jit_types
-  class
-  jit_typeinfo
-  {
-    // ----- Constructor/destructor (singleton pattern) -----
-
-  public:
-
-    ~jit_typeinfo (void);
-
-  private:
-
-    static jit_typeinfo& instance (void);
-    jit_typeinfo (void);
-    static bool s_in_construction;
-
-    // ----- Registering types -----
-
-  public:
-
-    static jit_type *register_new_type (const std::string& name, jit_type *parent,
-                                        llvm::Type *llvm_type, bool skip_paren = false)
-    {
-      return instance ().do_register_new_type (name, parent, llvm_type, skip_paren);
-    }
-
-  private:
-
-    // List of all registered types
-    std::vector<jit_type*> m_id_to_type;
-
-    // Register a new type
-    jit_type *do_register_new_type (const std::string& name, jit_type *parent,
-                                    llvm::Type *llvm_type, bool skip_paren = false);
-
-    // ----- Base types -----
-
-  public:
-
-    static jit_type *get_any (void) { return instance ().m_any; }
-
-    static jit_type *get_matrix (void) { return instance ().m_matrix; }
-
-    static jit_type *get_scalar (void) { return instance ().m_scalar; }
-
-    static jit_type *get_scalar_ptr (void) { return instance ().m_scalar_ptr; }
-
-    static jit_type *get_any_ptr (void) { return instance ().m_any_ptr; }
-
-    static jit_type *get_range (void) { return instance ().m_range; }
-
-    static jit_type *get_string (void) { return instance ().m_string; }
-
-    static jit_type *get_bool (void) { return instance ().m_boolean; }
-
-    static jit_type *get_index (void) { return instance ().m_index; }
-
-    static jit_type *get_complex (void) { return instance ().m_complex; }
-
-    static jit_type *intN (std::size_t nbits) { return instance ().do_get_intN (nbits); }
-
-    // FIXME: do we really need these two ?
-    static llvm::Type *get_scalar_llvm (void) { return instance ().m_scalar->to_llvm (); }  // this one is weird
-
-    static llvm::Type *get_index_llvm (void)  { return instance ().m_index->to_llvm (); }  // this one is weird too
-
-  private:
-
-    // Base types as LLVM types
-
-    llvm::Type *m_any_t;
-    llvm::Type *m_bool_t;  // FIXME: should be "boolean_t", for consistency
-    llvm::Type *m_complex_t;
-    llvm::Type *m_index_t;
-    llvm::Type *m_scalar_t;
-    llvm::Type *m_string_t;
-
-    llvm::StructType *m_range_t;
-    llvm::StructType *m_matrix_t;
-
-    // Base types as jit_type objects)
-
-    jit_type *m_any;
-    jit_type *m_boolean;
-    jit_type *m_complex;
-    jit_type *m_index;
-    jit_type *m_scalar;
-    jit_type *m_string;
-
-    jit_type *m_range;
-    jit_type *m_matrix;
-
-    jit_type *m_scalar_ptr;  // a fake type for interfacing with C++
-    jit_type *m_any_ptr;     // a fake type for interfacing with C++ (bis)
-    jit_type *m_unknown_function;
-
-    // complex_ret is what is passed to C functions
-    // in order to get calling convention right
-    llvm::StructType *m_complex_ret;
-
-    // Get integer type from number of bits
-    jit_type *do_get_intN (std::size_t nbits) const;
-
-    // map container for integer types: int8, int16, etc.
-    // (note that they are also stored in id_to_types)
-    std::map<std::size_t, jit_type *> m_ints;
-
-    // ----- parenthesis subsref/subsasgn -----
-
-    friend jit_paren_subsref;
-    friend jit_paren_subsasgn;
-
-  public:
-
-    static const jit_operation& paren_subsref (void)   { return instance ().paren_subsref_fn; }
-    static const jit_operation& paren_subsasgn (void)  { return instance ().paren_subsasgn_fn; }
-
-  private:
-
-    jit_paren_subsref paren_subsref_fn;
-    jit_paren_subsasgn paren_subsasgn_fn;
-
-    // ----- Miscellaneous (FIXME: needs to be organized) -----
-
-  public:
-
-    // Get the jit_type of an octave_value
-    static jit_type *type_of (const octave_value &ov)
-    {
-      return instance ().do_type_of (ov);
-    };
-
-    // Get a unary or binary operation from its integer id
-    static const jit_operation& binary_op (int op)
-    {
-      return instance ().do_binary_op (op);
-    }
-
-    static const jit_operation& unary_op (int op)
-    {
-      return instance ().do_unary_op (op);
-    }
-
-    static const jit_operation& grab (void)
-    {
-      return instance ().m_grab_fn;
-    }
-
-    static const jit_function& get_grab (jit_type *type)
-    {
-      return instance ().m_grab_fn.overload (type);
-    }
-
-    static const jit_operation& release (void)
-    {
-      return instance ().m_release_fn;
-    }
-
-    static const jit_function& get_release (jit_type *type)
-    {
-      return instance ().m_release_fn.overload (type);
-    }
-
-    static const jit_operation& destroy (void)
-    {
-      return instance ().m_destroy_fn;
-    }
-
-    static const jit_operation& print_value (void)
-    {
-      return instance ().m_print_fn;
-    }
-
-    static const jit_operation& for_init (void)
-    {
-      return instance ().m_for_init_fn;
-    }
-
-    static const jit_operation& for_check (void)
-    {
-      return instance ().m_for_check_fn;
-    }
-
-    static const jit_operation& for_index (void)
-    {
-      return instance ().m_for_index_fn;
-    }
-
-    static const jit_operation& make_range (void)
-    {
-      return instance ().m_make_range_fn;
-    }
-
-    static const jit_operation& logically_true (void)
-    {
-      return instance ().m_logically_true_fn;
-    }
-
-    static const jit_operation& cast (jit_type *result)
-    {
-      return instance ().do_cast (result);
-    }
-
-    static const jit_function& cast (jit_type *to, jit_type *from)
-    {
-      return instance ().do_cast (to, from);
-    }
-
-    static llvm::Value *insert_error_check (llvm::IRBuilderD& bld)
-    {
-      return instance ().do_insert_error_check (bld);
-    }
-
-    static llvm::Value *insert_interrupt_check (llvm::IRBuilderD& bld)
-    {
-      return instance ().do_insert_interrupt_check (bld);
-    }
-
-    static const jit_operation& end (void)
-    {
-      return instance ().m_end_fn;
-    }
-
-    static const jit_function& end (jit_value *value, jit_value *idx,
-                                    jit_value *count)
-    {
-      return instance ().do_end (value, idx, count);
-    }
-
-    static const jit_operation& create_undef (void)
-    {
-      return instance ().m_create_undef_fn;
-    }
-
-    static llvm::Value *create_complex (llvm::Value *real, llvm::Value *imag)
-    {
-      return instance ().complex_new (real, imag);
-    }
-
-    static llvm::Value *pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx)
-    {
-      return instance ().do_pack_complex (bld, cplx);
-    }
-
-    static llvm::Value *unpack_complex (llvm::IRBuilderD& bld,
-                                        llvm::Value *result);
-
-  private:
-
-    jit_type * do_type_of (const octave_value& ov) const;
-
-    const jit_operation& do_binary_op (int op) const
-    {
-      assert (static_cast<std::size_t> (op) < m_binary_ops.size ());
-      return m_binary_ops[op];
-    }
-
-    const jit_operation& do_unary_op (int op) const
-    {
-      assert (static_cast<std::size_t> (op) < m_unary_ops.size ());
-      return m_unary_ops[op];
-    }
-
-    const jit_operation& do_cast (jit_type *to)
-    {
-      static jit_operation null_function ("null_function");
-      if (! to)
-        return null_function;
-
-      std::size_t id = to->type_id ();
-      if (id >= m_casts.size ())
-        return null_function;
-      return m_casts[id];
-    }
-
-    const jit_function& do_cast (jit_type *to, jit_type *from)
-    {
-      return do_cast (to).overload (from);
-    }
-
-    const jit_function& do_end (jit_value *value, jit_value *index,
-                                jit_value *count);
-
-    void add_print (jit_type *ty, void *fptr);
-
-    void add_binary_op (jit_type *ty, int op, int llvm_op);
-
-    void add_binary_icmp (jit_type *ty, int op, int llvm_op);
-
-    void add_binary_fcmp (jit_type *ty, int op, int llvm_op);
-
-    // type signature vector
-    typedef std::vector<jit_type *> signature_vec;
-
-    // create a function with an external calling convention
-    // forces the function pointer to be specified
-    template <typename T>
-    jit_function create_external (T fn, const llvm::Twine& name,
-                                  jit_type * ret, const signature_vec& args
-                                  = signature_vec ()) const;
-
-    template <typename T, typename ...Args>
-    jit_function create_external (T fn, const llvm::Twine& name,
-                                  jit_type * ret, signature_vec& args,
-                                  jit_type * arg1, Args... other_args) const
-    {
-      args.push_back (arg1);
-      return create_external (fn, name, ret, args, other_args...);
-    }
-
-    template <typename T, typename ...Args>
-    jit_function create_external (T fn, const llvm::Twine& name, jit_type *ret,
-                                  jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return create_external (fn, name, ret, args, other_args...);
-    }
-
-    // create an internal calling convention (a function defined in llvm)
-    jit_function create_internal (const llvm::Twine& name, jit_type *ret,
-                                  const signature_vec& args
-                                  = signature_vec ()) const
-    {
-      return jit_function (m_base_jit_module, jit_convention::internal,
-                           name, ret, args);
-    }
-
-    template <typename ...Args>
-    jit_function create_internal (const llvm::Twine& name, jit_type *ret,
-                                  signature_vec& args,
-                                  jit_type * arg1, Args... other_args) const
-    {
-      args.push_back (arg1);
-      return create_internal (name, ret, args, other_args...);
-    }
-
-    template <typename ...Args>
-    jit_function create_internal (const llvm::Twine& name, jit_type *ret,
-                                  jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return create_internal (name, ret, args, other_args...);
-    }
-
-    jit_function create_identity (jit_type *type);
-
-    llvm::Value * do_insert_error_check (llvm::IRBuilderD& bld);
-
-    llvm::Value * do_insert_interrupt_check (llvm::IRBuilderD& bld);
-
-    void add_builtin (const std::string& name);
-
-    void register_intrinsic (const std::string& name, std::size_t id,
-                             jit_type *result, jit_type *arg0)
-    {
-      std::vector<jit_type *> args (1, arg0);
-      register_intrinsic (name, id, result, args);
-    }
-
-    void register_intrinsic (const std::string& name, std::size_t id, jit_type *result,
-                             const std::vector<jit_type *>& args);
-
-    void register_generic (const std::string& name, jit_type *result,
-                           jit_type *arg0)
-    {
-      std::vector<jit_type *> args (1, arg0);
-      register_generic (name, result, args);
-    }
-
-    void register_generic (const std::string& name, jit_type *result,
-                           const std::vector<jit_type *>& args);
-
-    octave_builtin * find_builtin (const std::string& name);
-
-    jit_function mirror_binary (const jit_function& fn);
-
-    llvm::Function * wrap_complex (llvm::Function *wrap);
-
-    llvm::Value * complex_real (llvm::Value *cx);
-
-    llvm::Value * complex_real (llvm::Value *cx, llvm::Value *real);
-
-    llvm::Value * complex_imag (llvm::Value *cx);
-
-    llvm::Value * complex_imag (llvm::Value *cx, llvm::Value *imag);
-
-    llvm::Value * complex_new (llvm::Value *real, llvm::Value *imag);
-
-    llvm::Value *do_pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) const;
-
-    int m_next_id;
-
-    llvm::GlobalVariable *m_lerror_state;
-    llvm::GlobalVariable *m_loctave_interrupt_state;
-
-    llvm::Type *m_sig_atomic_type;
-
-    std::map<std::string, jit_type *> m_builtins;
-
-    std::vector<jit_operation> m_binary_ops;
-    std::vector<jit_operation> m_unary_ops;
-    jit_operation m_grab_fn;
-    jit_operation m_release_fn;
-    jit_operation m_destroy_fn;
-    jit_operation m_print_fn;
-    jit_operation m_for_init_fn;
-    jit_operation m_for_check_fn;
-    jit_operation m_for_index_fn;
-    jit_operation m_logically_true_fn;
-    jit_operation m_make_range_fn;
-    jit_operation m_end1_fn;
-    jit_operation m_end_fn;
-    jit_operation m_create_undef_fn;
-
-    jit_function m_any_call;
-
-    // type id -> cast function TO that type
-    std::vector<jit_operation> m_casts;
-
-    // type id -> identity function
-    std::vector<jit_function> m_identities;
-
-    jit_module *m_base_jit_module;
-
-    llvm::IRBuilderD *m_builder_ptr;
-    llvm::IRBuilderD& m_builder;
-  };
-}
-
-#endif
-#endif
--- a/libinterp/parse-tree/jit-util.cc	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-// defines required by llvm
-#define __STDC_LIMIT_MACROS
-#define __STDC_CONSTANT_MACROS
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined (HAVE_LLVM)
-
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-#  include <llvm/IR/Value.h>
-#else
-#  include <llvm/Value.h>
-#endif
-
-#include <llvm/Support/raw_os_ostream.h>
-
-namespace octave
-{
-  std::ostream&
-  operator<< (std::ostream& os, const llvm::Value& v)
-  {
-    llvm::raw_os_ostream llvm_out (os);
-    v.print (llvm_out);
-    return os;
-  }
-}
-
-#endif
--- a/libinterp/parse-tree/jit-util.h	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-// Some utility classes and functions used throughout jit
-
-#if ! defined (octave_jit_util_h)
-#define octave_jit_util_h 1
-
-#include "octave-config.h"
-
-#if defined (HAVE_LLVM)
-
-#include <stdexcept>
-
-#if defined (HAVE_LLVM_IR_DATALAYOUT_H) || defined (HAVE_LLVM_DATALAYOUT_H)
-#  define HAVE_LLVM_DATALAYOUT
-#endif
-
-// we don't want to include llvm headers here, as they require
-// __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS be defined in the entire
-// compilation unit
-namespace llvm
-{
-  class Value;
-  class Module;
-  class ExecutionEngine;
-  class Function;
-  class BasicBlock;
-  class LLVMContext;
-  class Type;
-  class StructType;
-  class FunctionType;
-  class Twine;
-  class GlobalValue;
-  class GlobalVariable;
-  class TerminatorInst;
-  class PHINode;
-  class TargetMachine;
-
-  class ConstantFolder;
-
-#if defined  LLVM_IRBUILDER_HAS_TWO_TEMPLATE_ARGS
-
-  class IRBuilderDefaultInserter;
-
-  template <typename T, typename Inserter>
-  class IRBuilder;
-
-  typedef IRBuilder<ConstantFolder, IRBuilderDefaultInserter>
-    IRBuilderD;
-
-#else
-
-  template <bool preserveNames>
-  class IRBuilderDefaultInserter;
-
-  template <bool preserveNames, typename T, typename Inserter>
-  class IRBuilder;
-
-  typedef IRBuilder<true, ConstantFolder, IRBuilderDefaultInserter<true>>
-    IRBuilderD;
-
-#endif
-}
-
-// some octave classes that are not (yet) in the octave namespace
-class octave_base_value;
-class octave_builtin;
-class octave_value;
-class tree;
-class tree_expression;
-
-namespace octave
-{
-  // thrown when we should give up on JIT and interpret
-  class jit_fail_exception : public std::runtime_error
-  {
-  public:
-
-    jit_fail_exception (void)
-      : std::runtime_error ("unknown"), m_known (false)
-    { }
-
-    jit_fail_exception (const std::string& reason)
-      : std::runtime_error (reason), m_known (true)
-    { }
-
-    bool known (void) const { return m_known; }
-
-  private:
-
-    bool m_known;
-  };
-
-  // llvm doesn't provide this, and it's really useful for debugging
-  std::ostream& operator<< (std::ostream& os, const llvm::Value& v);
-
-  template <typename HOLDER_T, typename SUB_T>
-  class jit_internal_node;
-
-  // jit_internal_list and jit_internal_node implement generic embedded doubly
-  // linked lists.  List items extend from jit_internal_list, and can be placed
-  // in nodes of type jit_internal_node.  We use CRTP twice.
-
-  template <typename LIST_T, typename NODE_T>
-  class
-  jit_internal_list
-  {
-    friend class jit_internal_node<LIST_T, NODE_T>;
-
-  public:
-
-    jit_internal_list (void)
-      : m_use_head (0), m_use_tail (0), m_use_count (0)
-    { }
-
-    virtual ~jit_internal_list (void)
-    {
-      while (m_use_head)
-        m_use_head->stash_value (0);
-    }
-
-    NODE_T * first_use (void) const { return m_use_head; }
-
-    std::size_t use_count (void) const { return m_use_count; }
-
-  private:
-
-    NODE_T *m_use_head;
-    NODE_T *m_use_tail;
-    std::size_t m_use_count;
-  };
-
-  // a node for internal linked lists
-  template <typename LIST_T, typename NODE_T>
-  class
-  jit_internal_node
-  {
-  public:
-
-    typedef jit_internal_list<LIST_T, NODE_T> jit_ilist;
-
-    jit_internal_node (void)
-      : m_value (nullptr), m_next (nullptr), m_prev (nullptr)
-    { }
-
-    ~jit_internal_node (void) { remove (); }
-
-    LIST_T * value (void) const { return m_value; }
-
-    void stash_value (LIST_T *avalue)
-    {
-      remove ();
-
-      m_value = avalue;
-
-      if (m_value)
-        {
-          jit_ilist *ilist = m_value;
-          NODE_T *sthis = static_cast<NODE_T *> (this);
-          if (ilist->m_use_head)
-            {
-              ilist->m_use_tail->m_next = sthis;
-              m_prev = ilist->m_use_tail;
-            }
-          else
-            ilist->m_use_head = sthis;
-
-          ilist->m_use_tail = sthis;
-          ++ilist->m_use_count;
-        }
-    }
-
-    NODE_T * next (void) const { return m_next; }
-
-    NODE_T * prev (void) const { return m_prev; }
-
-  private:
-
-    void remove (void)
-    {
-      if (m_value)
-        {
-          jit_ilist *ilist = m_value;
-          if (m_prev)
-            m_prev->m_next = m_next;
-          else
-            // we are the use_head
-            ilist->m_use_head = m_next;
-
-          if (m_next)
-            m_next->m_prev = m_prev;
-          else
-            // we are the use tail
-            ilist->m_use_tail = m_prev;
-
-          m_next = m_prev = 0;
-          --ilist->m_use_count;
-          m_value = 0;
-        }
-    }
-
-    LIST_T *m_value;
-    NODE_T *m_next;
-    NODE_T *m_prev;
-  };
-
-  // Use like: isa<jit_phi> (value)
-  // basically just a short cut type typing dyanmic_cast.
-  template <typename T, typename U>
-  bool isa (U *value)
-  {
-    return dynamic_cast<T *> (value);
-  }
-
-}
-
-#endif
-#endif
--- a/libinterp/parse-tree/module.mk	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/parse-tree/module.mk	Tue Aug 10 16:42:29 2021 -0400
@@ -3,9 +3,6 @@
   %reldir%/bp-table.h \
   %reldir%/comment-list.h \
   %reldir%/filepos.h \
-  %reldir%/jit-ir.h \
-  %reldir%/jit-typeinfo.h \
-  %reldir%/jit-util.h \
   %reldir%/lex.h \
   %reldir%/oct-lvalue.h \
   %reldir%/parse.h \
@@ -32,7 +29,6 @@
   %reldir%/pt-fcn-handle.h \
   %reldir%/pt-id.h \
   %reldir%/pt-idx.h \
-  %reldir%/pt-jit.h \
   %reldir%/pt-jump.h \
   %reldir%/pt-loop.h \
   %reldir%/pt-mat.h \
@@ -55,9 +51,6 @@
   %reldir%/anon-fcn-validator.cc \
   %reldir%/bp-table.cc \
   %reldir%/comment-list.cc \
-  %reldir%/jit-ir.cc \
-  %reldir%/jit-typeinfo.cc \
-  %reldir%/jit-util.cc \
   %reldir%/lex.ll \
   %reldir%/oct-gperf.h \
   %reldir%/oct-lvalue.cc \
@@ -84,7 +77,6 @@
   %reldir%/pt-fcn-handle.cc \
   %reldir%/pt-id.cc \
   %reldir%/pt-idx.cc \
-  %reldir%/pt-jit.cc \
   %reldir%/pt-loop.cc \
   %reldir%/pt-mat.cc \
   %reldir%/pt-misc.cc \
@@ -118,7 +110,6 @@
 
 %canon_reldir%_libparse_tree_la_CPPFLAGS = \
   $(libinterp_liboctinterp_la_CPPFLAGS) \
-  $(LLVM_CPPFLAGS) \
   $(OCTAVE_PARSER_CPPFLAGS)
 
 libinterp_EXTRA_DIST += \
--- a/libinterp/parse-tree/pt-eval.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -71,9 +71,6 @@
 #include "utils.h"
 #include "variables.h"
 
-//FIXME: This should be part of tree_evaluator
-#include "pt-jit.h"
-
 namespace octave
 {
   // Normal evaluator.
@@ -3069,11 +3066,6 @@
 
     octave_value rhs = expr->evaluate (*this);
 
-#if defined (HAVE_LLVM)
-    if (tree_jit::execute (cmd, rhs))
-      return;
-#endif
-
     if (rhs.is_undefined ())
       return;
 
@@ -3435,14 +3427,6 @@
           }
       }
 
-    // FIXME: Is this in the right place now?
-
-#if defined (HAVE_LLVM)
-    if (user_function.is_special_expr ()
-        && tree_jit::execute (user_function, args, retval))
-      return retval;
-#endif
-
     bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin,
                         nargout, user_function.takes_varargs (),
                         user_function.all_va_args (args));
@@ -4162,11 +4146,6 @@
         line++;
       }
 
-#if defined (HAVE_LLVM)
-    if (tree_jit::execute (cmd))
-      return;
-#endif
-
     unwind_protect_var<bool> upv (m_in_loop_command, true);
 
     tree_expression *expr = cmd.condition ();
@@ -4210,11 +4189,6 @@
         line++;
       }
 
-#if defined (HAVE_LLVM)
-    if (tree_jit::execute (cmd))
-      return;
-#endif
-
     unwind_protect_var<bool> upv (m_in_loop_command, true);
 
     tree_expression *expr = cmd.condition ();
--- a/libinterp/parse-tree/pt-jit.cc	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2936 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-#define __STDC_LIMIT_MACROS
-#define __STDC_CONSTANT_MACROS
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include <sstream>
-#include <string>
-
-#include "bp-table.h"
-#include "defun.h"
-#include "errwarn.h"
-#include "ov.h"
-#include "pager.h"
-#include "pt-all.h"
-#include "pt-jit.h"
-#include "sighandlers.h"
-#include "symtab.h"
-#include "variables.h"
-#include "interpreter-private.h"
-
-// Programming Note: As of hg id 2b2c8ac44cd2, this file builds with
-// LLVM 3.8 but not with 3.9 (or probably any later version).
-
-#if defined (HAVE_LLVM)
-
-#include <llvm/Analysis/CallGraph.h>
-#include <llvm/Analysis/Passes.h>
-
-#if defined (HAVE_LLVM_IR_VERIFIER_H)
-#  include <llvm/IR/Verifier.h>
-#else
-#  include <llvm/Analysis/Verifier.h>
-#endif
-
-#if defined (HAVE_LLVM_ANALYSIS_BASICALIASANALYSIS_H)
-// In LLVM 3.8.x and later, we use createBasicAAWrapperPass from:
-#  include <llvm/Analysis/BasicAliasAnalysis.h>
-#endif
-// In LLVM 3.7.x and earlier, we use createBasicAliasAnalysisPass
-// from llvm/Analysis/Passes.h (already included above)
-
-#if defined (HAVE_LLVM_BITCODE_READERWRITER_H)
-// In LLVM <= 3.9, only one header for bitcode read/writer
-#  include <llvm/Bitcode/ReaderWriter.h>
-#else
-// Starting with LLVM 4.0, two separate headers
-#  include <llvm/Bitcode/BitcodeReader.h>
-#  include <llvm/Bitcode/BitcodeWriter.h>
-#endif
-
-#include <llvm/ExecutionEngine/ExecutionEngine.h>
-// old JIT, LLVM < 3.6.0
-// #include <llvm/ExecutionEngine/JIT.h>
-// MCJIT, LLVM >= 3.0.0
-#include <llvm/ExecutionEngine/MCJIT.h>
-#include "llvm/ExecutionEngine/SectionMemoryManager.h"
-
-#if defined (LEGACY_PASSMANAGER)
-#  include <llvm/IR/LegacyPassManager.h>
-#else
-#  include <llvm/PassManager.h>
-#endif
-
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-#  include <llvm/IR/LLVMContext.h>
-#  include <llvm/IR/Module.h>
-#  include <llvm/IR/Intrinsics.h>
-#else
-#  include <llvm/LLVMContext.h>
-#  include <llvm/Module.h>
-#  include <llvm/Intrinsics.h>
-#endif
-
-#if defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
-#  include <llvm/Support/IRBuilder.h>
-#elif defined(HAVE_LLVM_IR_IRBUILDER_H)
-#  include <llvm/IR/IRBuilder.h>
-#else
-#  include <llvm/IRBuilder.h>
-#endif
-
-#include <llvm/Support/raw_os_ostream.h>
-#include <llvm/Support/TargetSelect.h>
-
-#if defined (HAVE_LLVM_IR_DATALAYOUT_H)
-#  include <llvm/IR/DataLayout.h>
-#elif defined(HAVE_LLVM_DATALAYOUT_H)
-#  include <llvm/DataLayout.h>
-#else
-#  include <llvm/Target/TargetData.h>
-#endif
-
-#include <llvm/Transforms/IPO.h>
-#include <llvm/Transforms/Scalar.h>
-
-// Starting with LLVM 3.9.0, llvm::createGVNPass has
-// been moved to a new header file named GVN.h
-// (before that it was in llvm/Transforms/Scalar.h)
-#if defined (HAVE_LLVM_TRANSFORMS_SCALAR_GVN_H)
-#  include <llvm/Transforms/Scalar/GVN.h>
-#endif
-
-static bool Vdebug_jit = false;
-
-static bool Vjit_enable = false;
-
-static int Vjit_startcnt = 1000;
-
-static int Vjit_failcnt = 0;
-
-namespace octave
-{
-  namespace jit
-  {
-#if defined (LEGACY_PASSMANAGER)
-    typedef llvm::legacy::PassManager PassManager;
-    typedef llvm::legacy::FunctionPassManager FunctionPassManager;
-#else
-    typedef llvm::PassManager PassManager;
-    typedef llvm::FunctionPassManager FunctionPassManager;
-#endif
-  }
-
-  static llvm::IRBuilder<> builder (tree_jit::llvm_context);
-
-  static llvm::LLVMContext& context = tree_jit::llvm_context;
-
-  // -------------------- jit_break_exception --------------------
-
-  // jit_break is thrown whenever a branch we are converting has only breaks or
-  // continues.  This is because all code that follows a break or continue
-  // is dead.
-  class jit_break_exception : public std::exception
-  { };
-
-  // -------------------- jit_convert --------------------
-  jit_convert::jit_convert (tree& tee, jit_type *for_bounds)
-    : m_converting_function (false)
-  {
-    initialize (__get_current_scope__ ("jit_convert::jit_convert"));
-
-    if (for_bounds)
-      create_variable (next_for_bounds (false), for_bounds);
-
-    try
-      {
-        visit (tee);
-      }
-    catch (const jit_break_exception&)
-      { }
-
-    // breaks must have been handled by the top level loop
-    assert (m_breaks.empty ());
-    assert (m_continues.empty ());
-
-    m_block->append (m_factory.create<jit_branch> (m_final_block));
-    m_blocks.push_back (m_final_block);
-
-    for (auto iter = m_vmap.begin (); iter != m_vmap.end (); ++iter)
-      {
-        jit_variable *var = iter->second;
-        const std::string& name = var->name ();
-        if (name.size () && name[0] != '#')
-          m_final_block->append (m_factory.create<jit_store_argument> (var));
-      }
-
-    m_final_block->append (m_factory.create<jit_return> ());
-  }
-
-  jit_convert::jit_convert (octave_user_function& fcn,
-                            const std::vector<jit_type *>& args)
-    : m_converting_function (true)
-  {
-    initialize (fcn.scope ());
-
-    tree_parameter_list *plist = fcn.parameter_list ();
-    tree_parameter_list *rlist = fcn.return_list ();
-    if (plist && plist->takes_varargs ())
-      throw jit_fail_exception ("varags not supported");
-
-    if (rlist && (rlist->size () > 1 || rlist->takes_varargs ()))
-      throw jit_fail_exception ("multiple returns not supported");
-
-    if (plist)
-      {
-        auto piter = plist->begin ();
-        for (std::size_t i = 0; i < args.size (); ++i, ++piter)
-          {
-            if (piter == plist->end ())
-              throw jit_fail_exception ("Too many parameter to function");
-
-            tree_decl_elt *elt = *piter;
-            std::string name = elt->name ();
-            create_variable (name, args[i]);
-          }
-      }
-
-    jit_value *return_value = nullptr;
-    bool all_breaking = false;
-    if (fcn.is_special_expr ())
-      {
-        tree_expression *expr = fcn.special_expr ();
-        if (expr)
-          {
-            jit_variable *retvar = get_variable ("#return");
-            jit_value *retval = nullptr;
-            try
-              {
-                retval = visit (expr);
-              }
-            catch (const jit_break_exception&)
-              { }
-
-            if (m_breaks.size () || m_continues.size ())
-              throw jit_fail_exception ("break/continue not supported in "
-                                        "anonymous functions");
-
-            m_block->append (m_factory.create<jit_assign> (retvar, retval));
-            return_value = retvar;
-          }
-      }
-    else
-      {
-        try
-          {
-            visit_statement_list (*fcn.body ());
-          }
-        catch (const jit_break_exception&)
-          {
-            all_breaking = true;
-          }
-
-        // the user may use break or continue to exit the function
-        finish_breaks (m_final_block, m_continues);
-        finish_breaks (m_final_block, m_breaks);
-      }
-
-    if (! all_breaking)
-      m_block->append (m_factory.create<jit_branch> (m_final_block));
-
-    m_blocks.push_back (m_final_block);
-    m_block = m_final_block;
-
-    if (! return_value && rlist && rlist->size () == 1)
-      {
-        tree_decl_elt *elt = rlist->front ();
-        return_value = get_variable (elt->name ());
-      }
-
-    // FIXME: We should use live range analysis to delete variables where
-    // needed.  For now we just delete everything at the end of the function.
-    for (auto iter = m_vmap.begin ();
-         iter != m_vmap.end ();
-         ++iter)
-      {
-        if (iter->second != return_value)
-          {
-            jit_call *call;
-            call = m_factory.create<jit_call> (&jit_typeinfo::destroy,
-                                               iter->second);
-            m_final_block->append (call);
-          }
-      }
-
-    if (return_value)
-      m_final_block->append (m_factory.create<jit_return> (return_value));
-    else
-      m_final_block->append (m_factory.create<jit_return> ());
-  }
-
-  void
-  jit_convert::visit_anon_fcn_handle (tree_anon_fcn_handle&)
-  {
-    throw jit_fail_exception ("No visit_anon_fcn_handle implementation");
-  }
-
-  void
-  jit_convert::visit_argument_list (tree_argument_list&)
-  {
-    throw jit_fail_exception ("No visit_argument_list implementation");
-  }
-
-  void
-  jit_convert::visit_binary_expression (tree_binary_expression& be)
-  {
-    tree_expression *lhs = be.lhs ();
-    jit_value *lhsv = visit (lhs);
-
-    tree_expression *rhs = be.rhs ();
-    jit_value *rhsv = visit (rhs);
-
-    const jit_operation& fn = jit_typeinfo::binary_op (be.op_type ());
-    m_result = create_checked (fn, lhsv, rhsv);
-  }
-
-  void
-  jit_convert::visit_boolean_expression (tree_boolean_expression& be)
-  {
-    bool is_and = be.op_type () == tree_boolean_expression::bool_and;
-
-    std::string short_name = next_shortcircut_result ();
-    jit_variable *short_result = m_factory.create<jit_variable> (short_name);
-    m_vmap[short_name] = short_result;
-
-    jit_block *done = m_factory.create<jit_block> (m_block->name ());
-    tree_expression *lhs = be.lhs ();
-    jit_value *lhsv = visit (lhs);
-    lhsv = create_checked (&jit_typeinfo::logically_true, lhsv);
-
-    jit_block *short_early = m_factory.create<jit_block> ("short_early");
-    m_blocks.push_back (short_early);
-
-    jit_block *short_cont = m_factory.create<jit_block> ("short_cont");
-
-    if (is_and)
-      m_block->append (m_factory.create<jit_cond_branch> (lhsv, short_cont,
-                                                      short_early));
-    else
-      m_block->append (m_factory.create<jit_cond_branch> (lhsv, short_early,
-                                                      short_cont));
-
-    m_block = short_early;
-
-    jit_value *early_result = m_factory.create<jit_const_bool> (! is_and);
-    m_block->append (m_factory.create<jit_assign> (short_result, early_result));
-    m_block->append (m_factory.create<jit_branch> (done));
-
-    m_blocks.push_back (short_cont);
-    m_block = short_cont;
-
-    tree_expression *rhs = be.rhs ();
-    jit_value *rhsv = visit (rhs);
-    rhsv = create_checked (&jit_typeinfo::logically_true, rhsv);
-    m_block->append (m_factory.create<jit_assign> (short_result, rhsv));
-    m_block->append (m_factory.create<jit_branch> (done));
-
-    m_blocks.push_back (done);
-    m_block = done;
-    m_result = short_result;
-  }
-
-  void
-  jit_convert::visit_break_command (tree_break_command&)
-  {
-    m_breaks.push_back (m_block);
-    throw jit_break_exception ();
-  }
-
-  void
-  jit_convert::visit_colon_expression (tree_colon_expression& expr)
-  {
-    // in the further we need to add support for classes and deal with rvalues
-    jit_value *base = visit (expr.base ());
-    jit_value *limit = visit (expr.limit ());
-    jit_value *increment;
-    tree_expression *tinc = expr.increment ();
-
-    if (tinc)
-      increment = visit (tinc);
-    else
-      increment = m_factory.create<jit_const_scalar> (1);
-
-    m_result = m_block->append (m_factory.create<jit_call> (jit_typeinfo::make_range,
-                                                      base, limit, increment));
-  }
-
-  void
-  jit_convert::visit_continue_command (tree_continue_command&)
-  {
-    m_continues.push_back (m_block);
-    throw jit_break_exception ();
-  }
-
-  void
-  jit_convert::visit_decl_command (tree_decl_command&)
-  {
-    throw jit_fail_exception ("No visit_decl_command implementation");
-  }
-
-  void
-  jit_convert::visit_decl_elt (tree_decl_elt&)
-  {
-    throw jit_fail_exception ("No visit_decl_elt implementation");
-  }
-
-  void
-  jit_convert::visit_decl_init_list (tree_decl_init_list&)
-  {
-    throw jit_fail_exception ("No visit_decl_init_list implementation");
-  }
-
-  void
-  jit_convert::visit_simple_for_command (tree_simple_for_command& cmd)
-  {
-    // Note we do an initial check to see if the loop will run at least once.
-    // This allows us to get better type inference bounds on variables defined
-    // and used only inside the for loop (e.g., the index variable)
-
-    // If we are a nested for loop we need to store the previous breaks
-    unwind_protect frame;
-    frame.protect_var (m_breaks);
-    frame.protect_var (m_continues);
-    m_breaks.clear ();
-    m_continues.clear ();
-
-    // Need a variable for our iterator, because it is used in multiple blocks
-    std::string iter_name = next_iterator ();
-    jit_variable *iterator = m_factory.create<jit_variable> (iter_name);
-    m_factory.create<jit_variable> (iter_name);
-    m_vmap[iter_name] = iterator;
-
-    jit_block *body = m_factory.create<jit_block> ("for_body");
-    jit_block *tail = m_factory.create<jit_block> ("for_tail");
-
-    // Do control expression, iter init, and condition check in prev_block
-    // (block).
-    // if we are the top level for loop, the bounds is an input argument.
-    jit_value *control = find_variable (next_for_bounds ());
-    if (! control)
-      control = visit (cmd.control_expr ());
-    jit_call *init_iter = m_factory.create<jit_call> (jit_typeinfo::for_init,
-                                                      control);
-    m_block->append (init_iter);
-    m_block->append (m_factory.create<jit_assign> (iterator, init_iter));
-
-    jit_call *check = m_factory.create<jit_call> (jit_typeinfo::for_check,
-                                                  control, iterator);
-    m_block->append (check);
-    m_block->append (m_factory.create<jit_cond_branch> (check, body, tail));
-
-    m_blocks.push_back (body);
-    m_block = body;
-
-    // compute the syntactical iterator
-    jit_call *idx_rhs = m_factory.create<jit_call> (jit_typeinfo::for_index,
-                                                    control, iterator);
-    m_block->append (idx_rhs);
-    do_assign (cmd.left_hand_side (), idx_rhs);
-
-    // do loop
-    tree_statement_list *pt_body = cmd.body ();
-    bool all_breaking = false;
-    try
-      {
-        pt_body->accept (*this);
-      }
-    catch (const jit_break_exception&)
-      {
-        if (m_continues.empty ())
-          {
-            // WTF are you doing user?  Every branch was a break, why did you
-            // have a loop???  Users are silly people...
-            finish_breaks (tail, m_breaks);
-            m_blocks.push_back (tail);
-            m_block = tail;
-            return;
-          }
-
-        all_breaking = true;
-      }
-
-    // check our condition, continues jump to this block
-    jit_block *check_block = m_factory.create<jit_block> ("for_check");
-    m_blocks.push_back (check_block);
-
-    jit_block *interrupt_check = m_factory.create<jit_block> ("for_interrupt");
-    m_blocks.push_back (interrupt_check);
-
-    if (! all_breaking)
-      m_block->append (m_factory.create<jit_branch> (check_block));
-    finish_breaks (check_block, m_continues);
-
-    m_block = check_block;
-    const jit_operation& add_fn = jit_typeinfo::binary_op (octave_value::op_add);
-    jit_value *one = m_factory.create<jit_const_index> (1);
-    jit_call *iter_inc = m_factory.create<jit_call> (add_fn, iterator, one);
-    m_block->append (iter_inc);
-    m_block->append (m_factory.create<jit_assign> (iterator, iter_inc));
-    check = m_block->append (m_factory.create<jit_call> (jit_typeinfo::for_check,
-                                                         control, iterator));
-    m_block->append (m_factory.create<jit_cond_branch> (check, interrupt_check,
-                                                        tail));
-
-    m_block = interrupt_check;
-    jit_error_check *ec
-      = m_factory.create<jit_error_check> (jit_error_check::var_interrupt,
-                                           body, m_final_block);
-    m_block->append (ec);
-
-    // breaks will go to our tail
-    m_blocks.push_back (tail);
-    finish_breaks (tail, m_breaks);
-    m_block = tail;
-  }
-
-  void
-  jit_convert::visit_complex_for_command (tree_complex_for_command&)
-  {
-    throw jit_fail_exception ("No visit_complex_for_command implementation");
-  }
-
-  void
-  jit_convert::visit_octave_user_script (octave_user_script&)
-  {
-    throw jit_fail_exception ("No visit_octave_user_script implementation");
-  }
-
-  void
-  jit_convert::visit_octave_user_function (octave_user_function&)
-  {
-    throw jit_fail_exception ("No visit_octave_user_function implementation");
-  }
-
-  void
-  jit_convert::visit_octave_user_function_header (octave_user_function&)
-  {
-    throw jit_fail_exception ("No visit_octave_user_function_header implementation");
-  }
-
-  void
-  jit_convert::visit_octave_user_function_trailer (octave_user_function&)
-  {
-    throw jit_fail_exception ("No visit_octave_user_function_trailer implementation");
-  }
-
-  void
-  jit_convert::visit_function_def (tree_function_def&)
-  {
-    throw jit_fail_exception ("No visit_function_def implementation");
-  }
-
-  void
-  jit_convert::visit_identifier (tree_identifier& ti)
-  {
-    if (ti.has_magic_end ())
-      {
-        if (! m_end_context.size ())
-          throw jit_fail_exception ("Illegal end");
-        m_result = m_block->append (m_factory.create<jit_magic_end> (m_end_context));
-      }
-    else
-      {
-        jit_variable *var = get_variable (ti.name ());
-        jit_instruction *instr;
-        instr = m_factory.create<jit_call> (&jit_typeinfo::grab, var);
-        m_result = m_block->append (instr);
-      }
-  }
-
-  void
-  jit_convert::visit_if_clause (tree_if_clause&)
-  {
-    throw jit_fail_exception ("No visit_if_clause implementation");
-  }
-
-  void
-  jit_convert::visit_if_command_list (tree_if_command_list& lst)
-  {
-    tree_if_clause *last = lst.back ();
-    std::size_t last_else = static_cast<std::size_t> (last->is_else_clause ());
-
-    // entry_blocks represents the block you need to enter in order to execute
-    // the condition check for the ith clause.  For the else, it is simple the
-    // else body.  If there is no else body, then it is padded with the tail.
-    std::vector<jit_block *> entry_blocks (lst.size () + 1 - last_else);
-    entry_blocks[0] = m_block;
-
-    // Need to construct blocks first, because they have jumps to each other.
-    auto iter = lst.begin ();
-    ++iter;
-    for (std::size_t i = 1; iter != lst.end (); ++iter, ++i)
-      {
-        tree_if_clause *tic = *iter;
-        if (tic->is_else_clause ())
-          entry_blocks[i] = m_factory.create<jit_block> ("else");
-        else
-          entry_blocks[i] = m_factory.create<jit_block> ("ifelse_cond");
-      }
-
-    jit_block *tail = m_factory.create<jit_block> ("if_tail");
-    if (! last_else)
-      entry_blocks[entry_blocks.size () - 1] = tail;
-
-    // each branch in the if statement will have different breaks/continues
-    block_list current_breaks = m_breaks;
-    block_list current_continues = m_continues;
-    m_breaks.clear ();
-    m_continues.clear ();
-
-    std::size_t num_incoming = 0; // number of incoming blocks to our tail
-    iter = lst.begin ();
-    for (std::size_t i = 0; iter != lst.end (); ++iter, ++i)
-      {
-        tree_if_clause *tic = *iter;
-        m_block = entry_blocks[i];
-        assert (m_block);
-
-        if (i) // the first block is prev_block, so it has already been added
-          m_blocks.push_back (entry_blocks[i]);
-
-        if (! tic->is_else_clause ())
-          {
-            tree_expression *expr = tic->condition ();
-            jit_value *cond = visit (expr);
-            jit_call *check = create_checked (&jit_typeinfo::logically_true,
-                                              cond);
-            jit_block *body = m_factory.create<jit_block> (i == 0 ? "if_body"
-                                                         : "ifelse_body");
-            m_blocks.push_back (body);
-
-            jit_instruction *br = m_factory.create<jit_cond_branch> (check,
-                                                                     body,
-                                                                     entry_blocks[i + 1]);
-            m_block->append (br);
-            m_block = body;
-          }
-
-        tree_statement_list *stmt_lst = tic->commands ();
-        assert (stmt_lst); // jwe: Can this be null?
-
-        try
-          {
-            stmt_lst->accept (*this);
-            ++num_incoming;
-            m_block->append (m_factory.create<jit_branch> (tail));
-          }
-        catch (const jit_break_exception&)
-          { }
-
-        current_breaks.splice (current_breaks.end (), m_breaks);
-        current_continues.splice (current_continues.end (), m_continues);
-      }
-
-    m_breaks.splice (m_breaks.end (), current_breaks);
-    m_continues.splice (m_continues.end (), current_continues);
-
-    if (num_incoming || ! last_else)
-      {
-        m_blocks.push_back (tail);
-        m_block = tail;
-      }
-    else
-      // every branch broke, so we don't have a tail
-      throw jit_break_exception ();
-  }
-
-  void
-  jit_convert::visit_index_expression (tree_index_expression& exp)
-  {
-    m_result = resolve (exp);
-  }
-
-  void
-  jit_convert::visit_matrix (tree_matrix&)
-  {
-    throw jit_fail_exception ("No visit_matrix implementation");
-  }
-
-  void
-  jit_convert::visit_cell (tree_cell&)
-  {
-    throw jit_fail_exception ("No visit_cell implementation");
-  }
-
-  void
-  jit_convert::visit_multi_assignment (tree_multi_assignment&)
-  {
-    throw jit_fail_exception ("No visit_multi_assignment implementation");
-  }
-
-  void
-  jit_convert::visit_no_op_command (tree_no_op_command&)
-  {
-    throw jit_fail_exception ("No visit_no_op_command implementation");
-  }
-
-  void
-  jit_convert::visit_constant (tree_constant& tc)
-  {
-    octave_value v = tc.value ();
-
-    jit_type *ty = jit_typeinfo::type_of (v);
-
-    if (ty == jit_typeinfo::get_scalar ())
-      {
-        double dv = v.double_value ();
-        m_result = m_factory.create<jit_const_scalar> (dv);
-      }
-    else if (ty == jit_typeinfo::get_range ())
-      {
-        range<double> rv = v.range_value ();
-        m_result = m_factory.create<jit_const_range> (rv);
-      }
-    else if (ty == jit_typeinfo::get_complex ())
-      {
-        Complex cv = v.complex_value ();
-        m_result = m_factory.create<jit_const_complex> (cv);
-      }
-    else
-      throw jit_fail_exception ("Unknown constant");
-  }
-
-  void
-  jit_convert::visit_fcn_handle (tree_fcn_handle&)
-  {
-    throw jit_fail_exception ("No visit_fcn_handle implementation");
-  }
-
-  void
-  jit_convert::visit_parameter_list (tree_parameter_list&)
-  {
-    throw jit_fail_exception ("No visit_parameter_list implementation");
-  }
-
-  void
-  jit_convert::visit_postfix_expression (tree_postfix_expression& tpe)
-  {
-    octave_value::unary_op etype = tpe.op_type ();
-    tree_expression *operand = tpe.operand ();
-    jit_value *operandv = visit (operand);
-
-    const jit_operation& fn = jit_typeinfo::unary_op (etype);
-    m_result = create_checked (fn, operandv);
-
-    if (etype == octave_value::op_incr || etype == octave_value::op_decr)
-      {
-        jit_value *ret = create_checked (&jit_typeinfo::grab, operandv);
-        do_assign (operand, m_result);
-        m_result = ret;
-      }
-  }
-
-  void
-  jit_convert::visit_prefix_expression (tree_prefix_expression& tpe)
-  {
-    octave_value::unary_op etype = tpe.op_type ();
-    tree_expression *operand = tpe.operand ();
-    const jit_operation& fn = jit_typeinfo::unary_op (etype);
-    m_result = create_checked (fn, visit (operand));
-
-    if (etype == octave_value::op_incr || etype == octave_value::op_decr)
-      do_assign (operand, m_result);
-  }
-
-  void
-  jit_convert::visit_return_command (tree_return_command&)
-  {
-    throw jit_fail_exception ("No visit_return_command implementation");
-  }
-
-  void
-  jit_convert::visit_simple_assignment (tree_simple_assignment& tsa)
-  {
-    tree_expression *rhs = tsa.right_hand_side ();
-    jit_value *rhsv = visit (rhs);
-    octave_value::assign_op op = tsa.op_type ();
-
-    if (op != octave_value::op_asn_eq)
-      {
-        // Do the equivalent binary operation, then assign.
-        // This is always correct, but it isn't always optimal.
-        tree_expression *lhs = tsa.left_hand_side ();
-        jit_value *lhsv = visit (lhs);
-        octave_value::binary_op bop = octave_value::assign_op_to_binary_op (op);
-        const jit_operation& fn = jit_typeinfo::binary_op (bop);
-        rhsv = create_checked (fn, lhsv, rhsv);
-      }
-
-    m_result = do_assign (tsa.left_hand_side (), rhsv);
-  }
-
-  void
-  jit_convert::visit_statement (tree_statement& stmt)
-  {
-    tree_command *cmd = stmt.command ();
-    tree_expression *expr = stmt.expression ();
-
-    if (cmd)
-      visit (cmd);
-    else
-      {
-        // stolen from tree_evaluator::visit_statement
-        bool do_bind_ans = false;
-
-        if (expr->is_identifier ())
-          {
-            tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
-
-            do_bind_ans = (! id->is_variable (m_scope.current_context ()));
-          }
-        else
-          do_bind_ans = (! expr->is_assignment_expression ());
-
-        jit_value *expr_result = visit (expr);
-
-        if (do_bind_ans)
-          do_assign ("ans", expr_result, expr->print_result ());
-        else if (expr->is_identifier () && expr->print_result ())
-          {
-            // FIXME: ugly hack, we need to come up with a way to pass
-            // nargout to visit_identifier
-            const jit_operation& fn = jit_typeinfo::print_value ();
-            jit_const_string *name = m_factory.create<jit_const_string>
-              (expr->name ());
-            m_block->append (m_factory.create<jit_call> (fn, name,
-                                                         expr_result));
-          }
-      }
-  }
-
-  void
-  jit_convert::visit_switch_case (tree_switch_case&)
-  {
-    throw jit_fail_exception ("No visit_switch_case implementation");
-  }
-
-  void
-  jit_convert::visit_switch_case_list (tree_switch_case_list&)
-  {
-    throw jit_fail_exception ("No visit_switch_case_list implementation");
-  }
-
-  void
-  jit_convert::visit_switch_command (tree_switch_command& cmd)
-  {
-    tree_switch_case_list *lst = cmd.case_list ();
-
-    // always visit switch expression
-    tree_expression *expr = cmd.switch_value ();
-    assert (expr && "Switch value can not be null");
-    jit_value *value = visit (expr);
-    assert (value);
-
-    std::size_t case_blocks_num = lst->size ();
-
-    if (! case_blocks_num)  // there's nothing to do
-      return;
-
-    // check for otherwise, it's interpreted as last 'else' condition
-    std::size_t has_otherwise = 0;
-    tree_switch_case *last = lst->back ();
-    if (last->is_default_case ())
-      has_otherwise = 1;
-
-    std::vector<jit_block *> entry_blocks (case_blocks_num+1 - has_otherwise);
-
-    // the first entry point is always the actual block.  Afterward, new blocks
-    // are created for every case and the otherwise branch
-    entry_blocks[0] = m_block;
-    for (std::size_t i = 1; i < case_blocks_num; ++i)
-      entry_blocks[i] = m_factory.create<jit_block> ("case_cond");
-
-    jit_block *tail = m_factory.create<jit_block> ("switch_tail");
-
-    // if there's no otherwise branch, the 'else' of the last branch
-    // has to point to the tail
-    if (! has_otherwise)
-      entry_blocks[entry_blocks.size()-1] = tail;
-
-    // each branch in the case statement will have different breaks/continues
-    block_list current_breaks = m_breaks;
-    block_list current_continues = m_continues;
-    m_breaks.clear ();
-    m_continues.clear ();
-
-    std::size_t num_incoming = 0; // number of incoming blocks to our tail
-
-    auto iter = lst->begin ();
-    for (std::size_t i = 0; i < case_blocks_num; ++iter, ++i)
-      {
-        tree_switch_case *twc = *iter;
-        m_block = entry_blocks[i]; // case_cond
-        assert (m_block);
-
-        if (i)
-          m_blocks.push_back (entry_blocks[i]);  // first block already pushed
-
-        if (! twc->is_default_case ())
-          {
-            // compare result of switch expression with actual case label
-            tree_expression *te = twc->case_label ();
-            jit_value *label = visit (te);
-            assert(label);
-
-            const jit_operation& fn = jit_typeinfo::binary_op (octave_value::op_eq);
-            jit_value *cond = create_checked (fn, value, label);
-            assert(cond);
-
-            jit_call *check = create_checked (&jit_typeinfo::logically_true,
-                                              cond);
-
-            jit_block *body = m_factory.create<jit_block> ("case_body");
-            m_blocks.push_back (body);
-
-            m_block->append (m_factory.create<jit_cond_branch> (check, body,
-                                                            entry_blocks[i+1]));
-            m_block = body; // case_body
-          }
-
-        tree_statement_list *stmt_lst = twc->commands ();
-        assert(stmt_lst);
-
-        try
-          {
-            stmt_lst->accept (*this);
-            num_incoming++;
-            m_block->append (m_factory.create<jit_branch> (tail));
-          }
-        catch (const jit_break_exception&)
-          { }
-
-        // each branch in the case statement will have different
-        // breaks/continues
-        current_breaks.splice (current_breaks.end (), m_breaks);
-        current_continues.splice (current_continues.end (), m_continues);
-      }
-
-    // each branch in the case statement will have different breaks/continues
-    m_breaks.splice (m_breaks.end (), current_breaks);
-    m_continues.splice (m_continues.end (), current_continues);
-
-    if (num_incoming || ! has_otherwise)
-      {
-        m_blocks.push_back (tail);
-        m_block = tail; // switch_tail
-      }
-    else
-      throw jit_break_exception ();   // every branch broke
-  }
-
-  void
-  jit_convert::visit_try_catch_command (tree_try_catch_command&)
-  {
-    throw jit_fail_exception ("No visit_try_catch_command implementation");
-  }
-
-  void
-  jit_convert::visit_unwind_protect_command (tree_unwind_protect_command&)
-  {
-    throw jit_fail_exception ("No visit_unwind_protect_command implementation");
-  }
-
-  void
-  jit_convert::visit_while_command (tree_while_command& wc)
-  {
-    unwind_protect frame;
-    frame.protect_var (m_breaks);
-    frame.protect_var (m_continues);
-    m_breaks.clear ();
-    m_continues.clear ();
-
-    jit_block *cond_check = m_factory.create<jit_block> ("while_cond_check");
-    m_block->append (m_factory.create<jit_branch> (cond_check));
-    m_blocks.push_back (cond_check);
-    m_block = cond_check;
-
-    tree_expression *expr = wc.condition ();
-    assert (expr && "While expression can not be null");
-    jit_value *check = visit (expr);
-    check = create_checked (&jit_typeinfo::logically_true, check);
-
-    jit_block *body = m_factory.create<jit_block> ("while_body");
-    m_blocks.push_back (body);
-
-    jit_block *tail = m_factory.create<jit_block> ("while_tail");
-    m_block->append (m_factory.create<jit_cond_branch> (check, body, tail));
-    m_block = body;
-
-    tree_statement_list *loop_body = wc.body ();
-    bool all_breaking = false;
-    if (loop_body)
-      {
-        try
-          {
-            loop_body->accept (*this);
-          }
-        catch (const jit_break_exception&)
-          {
-            all_breaking = true;
-          }
-      }
-
-    finish_breaks (tail, m_breaks);
-
-    if (! all_breaking || m_continues.size ())
-      {
-        jit_block *interrupt_check
-          = m_factory.create<jit_block> ("interrupt_check");
-        m_blocks.push_back (interrupt_check);
-        finish_breaks (interrupt_check, m_continues);
-        if (! all_breaking)
-          m_block->append (m_factory.create<jit_branch> (interrupt_check));
-
-        m_block = interrupt_check;
-        jit_error_check *ec
-          = m_factory.create<jit_error_check> (jit_error_check::var_interrupt,
-                                               cond_check, m_final_block);
-        m_block->append (ec);
-      }
-
-    m_blocks.push_back (tail);
-    m_block = tail;
-  }
-
-  void
-  jit_convert::visit_do_until_command (tree_do_until_command& duc)
-  {
-    unwind_protect frame;
-    frame.protect_var (m_breaks);
-    frame.protect_var (m_continues);
-    m_breaks.clear ();
-    m_continues.clear ();
-
-    jit_block *body = m_factory.create<jit_block> ("do_until_body");
-    jit_block *cond_check = m_factory.create<jit_block> ("do_until_cond_check");
-    jit_block *tail = m_factory.create<jit_block> ("do_until_tail");
-
-    m_block->append (m_factory.create<jit_branch> (body));
-    m_blocks.push_back (body);
-    m_block = body;
-
-    tree_statement_list *loop_body = duc.body ();
-    bool all_breaking = false;
-    if (loop_body)
-      {
-        try
-          {
-            loop_body->accept (*this);
-          }
-        catch (const jit_break_exception&)
-          {
-            all_breaking = true;
-          }
-      }
-
-    finish_breaks (tail, m_breaks);
-
-    if (! all_breaking || m_continues.size ())
-      {
-        jit_block *interrupt_check
-          = m_factory.create<jit_block> ("interrupt_check");
-        m_blocks.push_back (interrupt_check);
-        finish_breaks (interrupt_check, m_continues);
-        if (! all_breaking)
-          m_block->append (m_factory.create<jit_branch> (interrupt_check));
-
-        m_block = interrupt_check;
-        jit_error_check *ec
-          = m_factory.create<jit_error_check> (jit_error_check::var_interrupt,
-                                               cond_check, m_final_block);
-        m_block->append (ec);
-
-        m_blocks.push_back (cond_check);
-        m_block = cond_check;
-
-        tree_expression *expr = duc.condition ();
-        assert (expr && "Do-Until expression can not be null");
-        jit_value *check = visit (expr);
-        check = create_checked (&jit_typeinfo::logically_true, check);
-
-        m_block->append (m_factory.create<jit_cond_branch> (check, tail,
-                                                            body));
-      }
-
-    m_blocks.push_back (tail);
-    m_block = tail;
-  }
-
-  void
-  jit_convert::initialize (const symbol_scope& s)
-  {
-    m_scope = s;
-    m_iterator_count = 0;
-    m_for_bounds_count = 0;
-    m_short_count = 0;
-    jit_instruction::reset_ids ();
-
-    m_entry_block = m_factory.create<jit_block> ("body");
-    m_final_block = m_factory.create<jit_block> ("final");
-    m_blocks.push_back (m_entry_block);
-    m_entry_block->mark_alive ();
-    m_block = m_entry_block;
-  }
-
-  jit_call *
-  jit_convert::create_checked_impl (jit_call *ret)
-  {
-    m_block->append (ret);
-
-    jit_block *normal = m_factory.create<jit_block> (m_block->name ());
-    jit_error_check *check
-      = m_factory.create<jit_error_check> (jit_error_check::var_error_state,
-                                           ret, normal, m_final_block);
-    m_block->append (check);
-    m_blocks.push_back (normal);
-    m_block = normal;
-
-    return ret;
-  }
-
-  jit_variable *
-  jit_convert::find_variable (const std::string& vname) const
-  {
-    variable_map::const_iterator iter;
-    iter = m_vmap.find (vname);
-    return iter != m_vmap.end () ? iter->second : nullptr;
-  }
-
-  jit_variable *
-  jit_convert::get_variable (const std::string& vname)
-  {
-    jit_variable *ret = find_variable (vname);
-    if (ret)
-      return ret;
-
-    symbol_table& symtab = __get_symbol_table__ ("jit_convert::find_variable");
-
-    symbol_record record = m_scope.find_symbol (vname);
-    if (record.is_persistent () || record.is_global ())
-      throw jit_fail_exception ("Persistent and global not yet supported");
-
-    if (m_converting_function)
-      return create_variable (vname, jit_typeinfo::get_any (), false);
-    else
-      {
-        octave_value val = record.varval (m_scope.current_context ());
-        if (val.is_undefined ())
-          val = symtab.find_function (vname);
-
-        jit_type *type = jit_typeinfo::type_of (val);
-        m_bounds.push_back (type_bound (type, vname));
-
-        return create_variable (vname, type);
-      }
-  }
-
-  jit_variable *
-  jit_convert::create_variable (const std::string& vname, jit_type *type,
-                                bool isarg)
-  {
-    jit_variable *var = m_factory.create<jit_variable> (vname);
-
-    if (isarg)
-      {
-        jit_extract_argument *extract;
-        extract = m_factory.create<jit_extract_argument> (type, var);
-        m_entry_block->prepend (extract);
-      }
-    else
-      {
-        jit_call *init = m_factory.create<jit_call> (&jit_typeinfo::create_undef);
-        jit_assign *assign = m_factory.create<jit_assign> (var, init);
-        m_entry_block->prepend (assign);
-        m_entry_block->prepend (init);
-      }
-
-    return m_vmap[vname] = var;
-  }
-
-  std::string
-  jit_convert::next_name (const char *prefix, std::size_t& count, bool inc)
-  {
-    std::stringstream ss;
-    ss << prefix << count;
-    if (inc)
-      ++count;
-    return ss.str ();
-  }
-
-  jit_instruction *
-  jit_convert::resolve (tree_index_expression& exp, jit_value *extra_arg,
-                        bool lhs)
-  {
-    std::string type = exp.type_tags ();
-    if (! (type.size () == 1 && type[0] == '('))
-      throw jit_fail_exception ("Unsupported index operation");
-
-    std::list<tree_argument_list *> args = exp.arg_lists ();
-    if (args.size () != 1)
-      throw jit_fail_exception ("Bad number of arguments in "
-                                "tree_index_expression");
-
-    tree_argument_list *arg_list = args.front ();
-    if (! arg_list)
-      throw jit_fail_exception ("null argument list");
-
-    if (arg_list->size () < 1)
-      throw jit_fail_exception ("Empty arg_list");
-
-    tree_expression *tree_object = exp.expression ();
-    jit_value *object;
-    if (lhs)
-      {
-        tree_identifier *id = dynamic_cast<tree_identifier *> (tree_object);
-        if (! id)
-          throw jit_fail_exception ("expected identifier");
-        object = get_variable (id->name ());
-      }
-    else
-      object = visit (tree_object);
-
-    std::size_t narg = arg_list->size ();
-    auto iter = arg_list->begin ();
-    bool have_extra = extra_arg;
-    std::vector<jit_value *> call_args (narg + 1 + have_extra);
-    call_args[0] = object;
-
-    for (std::size_t idx = 0; iter != arg_list->end (); ++idx, ++iter)
-      {
-        unwind_action pop_end_context
-          (&std::vector<jit_magic_end::context>::pop_back, &m_end_context));
-
-        jit_magic_end::context ctx (m_factory, object, idx, narg);
-        m_end_context.push_back (ctx);
-        call_args[idx + 1] = visit (*iter);
-      }
-
-    if (extra_arg)
-      call_args[call_args.size () - 1] = extra_arg;
-
-    const jit_operation& fres = (lhs ? jit_typeinfo::paren_subsasgn ()
-                                 : jit_typeinfo::paren_subsref ());
-
-    return create_checked (fres, call_args);
-  }
-
-  jit_value *
-  jit_convert::do_assign (tree_expression *exp, jit_value *rhs, bool
-                          artificial)
-  {
-    if (! exp)
-      throw jit_fail_exception ("NULL lhs in assign");
-
-    if (isa<tree_identifier> (exp))
-      return do_assign (exp->name (), rhs, exp->print_result (), artificial);
-    else if (tree_index_expression *idx
-             = dynamic_cast<tree_index_expression *> (exp))
-      {
-        jit_value *new_object = resolve (*idx, rhs, true);
-        do_assign (idx->expression (), new_object, true);
-
-        // FIXME: Will not work for values that must be released/grabbed
-        return rhs;
-      }
-    else
-      throw jit_fail_exception ("Unsupported assignment");
-  }
-
-  jit_value *
-  jit_convert::do_assign (const std::string& lhs, jit_value *rhs,
-                          bool print, bool artificial)
-  {
-    jit_variable *var = get_variable (lhs);
-    jit_assign *assign = m_block->append (m_factory.create<jit_assign> (var,
-                                                                        rhs));
-
-    if (artificial)
-      assign->mark_artificial ();
-
-    if (print)
-      {
-        const jit_operation& print_fn = jit_typeinfo::print_value ();
-        jit_const_string *name = m_factory.create<jit_const_string> (lhs);
-        m_block->append (m_factory.create<jit_call> (print_fn, name, var));
-      }
-
-    return var;
-  }
-
-  jit_value *
-  jit_convert::visit (tree& tee)
-  {
-    unwind_protect frame;
-    frame.protect_var (m_result);
-
-    tee.accept (*this);
-    return m_result;
-  }
-
-  void
-  jit_convert::finish_breaks (jit_block *dest, const block_list& lst)
-  {
-    for (auto iter = lst.begin (); iter != lst.end (); ++iter)
-      {
-        jit_block *b = *iter;
-        b->append (m_factory.create<jit_branch> (dest));
-      }
-  }
-
-  // -------------------- jit_convert_llvm --------------------
-  llvm::Function *
-  jit_convert_llvm::convert_loop (const jit_module& module,
-                                  const jit_block_list& blocks,
-                                  const std::list<jit_value *>& constants,
-                                  const std::string& llvm_function_name)
-  {
-    m_converting_function = false;
-
-    // for now just init arguments from entry, later we will have to do
-    // something more interesting
-    jit_block *m_entry_block = blocks.front ();
-    for (auto iter = m_entry_block->begin ();
-         iter != m_entry_block->end (); ++iter)
-      if (jit_extract_argument *extract
-          = dynamic_cast<jit_extract_argument *> (*iter))
-        m_argument_vec.push_back (std::make_pair (extract->name (), true));
-
-    jit_type *any = jit_typeinfo::get_any ();
-
-    // argument is an array of octave_base_value*, or octave_base_value**
-    llvm::Type *arg_type = any->to_llvm (); // this is octave_base_value*
-    llvm::FunctionType *ft;
-    ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context),
-                                  arg_type->getPointerTo (), false);
-
-    m_function = module.create_llvm_function (ft, llvm_function_name);
-    try
-      {
-        m_prelude = llvm::BasicBlock::Create (context, "prelude", m_function);
-        builder.SetInsertPoint (m_prelude);
-
-        // The jitted function will have only one function argument, of
-        // octave_base_value** type
-        llvm::Value *arg = &*(m_function->arg_begin ());
-
-        for (std::size_t i = 0; i < m_argument_vec.size (); ++i)
-          {
-#if defined (LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_REQUIRES_TYPE)
-            // LLVM >= 3.7
-            llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg_type, arg, i);
-#else
-            // LLVM <= 3.6
-            llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg, i);
-#endif
-            m_arguments[m_argument_vec[i].first] = loaded_arg;
-          }
-
-        convert (blocks, constants);
-      }
-    catch (const jit_fail_exception&)
-      {
-        m_function->eraseFromParent ();
-        throw;
-      }
-
-    return m_function;
-  }
-
-  jit_function
-  jit_convert_llvm::convert_function (const jit_module& module,
-                                      const jit_block_list& blocks,
-                                      const std::list<jit_value *>& constants,
-                                      octave_user_function& fcn,
-                                      const std::vector<jit_type *>& args)
-  {
-    m_converting_function = true;
-
-    jit_block *m_final_block = blocks.back ();
-    jit_return *ret = dynamic_cast<jit_return *> (m_final_block->back ());
-    assert (ret);
-
-    m_creating = jit_function (&module, jit_convention::internal,
-                               "foobar", ret->result_type (), args);
-    m_function = m_creating.to_llvm ();
-
-    try
-      {
-        m_prelude = m_creating.new_block ("prelude");
-        builder.SetInsertPoint (m_prelude);
-
-        tree_parameter_list *plist = fcn.parameter_list ();
-        if (plist)
-          {
-            auto piter = plist->begin ();
-            auto pend = plist->end ();
-            for (std::size_t i = 0; i < args.size () && piter != pend; ++i, ++piter)
-              {
-                tree_decl_elt *elt = *piter;
-                std::string arg_name = elt->name ();
-                m_arguments[arg_name] = m_creating.argument (builder, i);
-              }
-          }
-
-        convert (blocks, constants);
-      }
-    catch (const jit_fail_exception&)
-      {
-        m_function->eraseFromParent ();
-        throw;
-      }
-
-    return m_creating;
-  }
-
-  void
-  jit_convert_llvm::convert (const jit_block_list& blocks,
-                             const std::list<jit_value *>& constants)
-  {
-    std::list<jit_block *>::const_iterator biter;
-    for (biter = blocks.begin (); biter != blocks.end (); ++biter)
-      {
-        jit_block *jblock = *biter;
-        llvm::BasicBlock *m_block = llvm::BasicBlock::Create (context,
-                                                            jblock->name (),
-                                                            m_function);
-        jblock->stash_llvm (m_block);
-      }
-
-    jit_block *first = *blocks.begin ();
-    builder.CreateBr (first->to_llvm ());
-
-    // constants aren't in the IR, we visit those first
-    for (auto iter = constants.begin (); iter != constants.end (); ++iter)
-      if (! isa<jit_instruction> (*iter))
-        visit (*iter);
-
-    // convert all instructions
-    for (biter = blocks.begin (); biter != blocks.end (); ++biter)
-      visit (*biter);
-
-    // now finish phi nodes
-    for (biter = blocks.begin (); biter != blocks.end (); ++biter)
-      {
-        jit_block& m_block = **biter;
-        for (auto piter = m_block.begin ();
-             piter != m_block.end () && isa<jit_phi> (*piter); ++piter)
-          {
-            jit_instruction *phi = *piter;
-            finish_phi (static_cast<jit_phi *> (phi));
-          }
-      }
-  }
-
-  void
-  jit_convert_llvm::finish_phi (jit_phi *phi)
-  {
-    llvm::PHINode *llvm_phi = phi->to_llvm ();
-    for (std::size_t i = 0; i < phi->argument_count (); ++i)
-      {
-        llvm::BasicBlock *pred = phi->incoming_llvm (i);
-        llvm_phi->addIncoming (phi->argument_llvm (i), pred);
-      }
-  }
-
-  void
-  jit_convert_llvm::visit (jit_const_string& cs)
-  {
-    cs.stash_llvm (builder.CreateGlobalStringPtr (cs.value ()));
-  }
-
-  void
-  jit_convert_llvm::visit (jit_const_bool& cb)
-  {
-    cb.stash_llvm (llvm::ConstantInt::get (cb.type_llvm (), cb.value ()));
-  }
-
-  void
-  jit_convert_llvm::visit (jit_const_scalar& cs)
-  {
-    cs.stash_llvm (llvm::ConstantFP::get (cs.type_llvm (), cs.value ()));
-  }
-
-  void
-  jit_convert_llvm::visit (jit_const_complex& cc)
-  {
-    llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
-    Complex value = cc.value ();
-    llvm::Value *real = llvm::ConstantFP::get (scalar_t, value.real ());
-    llvm::Value *imag = llvm::ConstantFP::get (scalar_t, value.imag ());
-    cc.stash_llvm (jit_typeinfo::create_complex (real, imag));
-  }
-
-  void jit_convert_llvm::visit (jit_const_index& ci)
-  {
-    ci.stash_llvm (llvm::ConstantInt::get (ci.type_llvm (), ci.value ()));
-  }
-
-  void
-  jit_convert_llvm::visit (jit_const_range& cr)
-  {
-    llvm::StructType *stype = llvm::cast<llvm::StructType>(cr.type_llvm ());
-    llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
-    llvm::Type *idx = jit_typeinfo::get_index_llvm ();
-    const jit_range& rng = cr.value ();
-
-    llvm::Constant *constants[4];
-    constants[0] = llvm::ConstantFP::get (scalar_t, rng.m_base);
-    constants[1] = llvm::ConstantFP::get (scalar_t, rng.m_limit);
-    constants[2] = llvm::ConstantFP::get (scalar_t, rng.m_inc);
-    constants[3] = llvm::ConstantInt::get (idx, rng.m_nelem);
-
-    llvm::Value *as_llvm;
-    as_llvm = llvm::ConstantStruct::get (stype,
-                                         llvm::makeArrayRef (constants, 4));
-    cr.stash_llvm (as_llvm);
-  }
-
-  void
-  jit_convert_llvm::visit (jit_block& b)
-  {
-    llvm::BasicBlock *m_block = b.to_llvm ();
-    builder.SetInsertPoint (m_block);
-    for (auto iter = b.begin (); iter != b.end (); ++iter)
-      visit (*iter);
-  }
-
-  void
-  jit_convert_llvm::visit (jit_branch& b)
-  {
-    b.stash_llvm (builder.CreateBr (b.successor_llvm ()));
-  }
-
-  void
-  jit_convert_llvm::visit (jit_cond_branch& cb)
-  {
-    llvm::Value *cond = cb.cond_llvm ();
-    llvm::Value *br;
-    br = builder.CreateCondBr (cond, cb.successor_llvm (0),
-                               cb.successor_llvm (1));
-    cb.stash_llvm (br);
-  }
-
-  void
-  jit_convert_llvm::visit (jit_call& call)
-  {
-    const jit_function& ol = call.overload ();
-
-    std::vector<jit_value *> args (call.arguments ().size ());
-    for (std::size_t i = 0; i < args.size (); ++i)
-      args[i] = call.argument (i);
-
-    llvm::Value *ret = ol.call (builder, args);
-    call.stash_llvm (ret);
-  }
-
-  void
-  jit_convert_llvm::visit (jit_extract_argument& extract)
-  {
-    llvm::Value *arg = m_arguments[extract.name ()];
-    assert (arg);
-
-    if (m_converting_function)
-      extract.stash_llvm (arg);
-    else
-      {
-        arg = builder.CreateLoad (arg);
-
-        const jit_function& ol = extract.overload ();
-        extract.stash_llvm (ol.call (builder, arg));
-      }
-  }
-
-  void
-  jit_convert_llvm::visit (jit_store_argument& store)
-  {
-    const jit_function& ol = store.overload ();
-    llvm::Value *arg_value = ol.call (builder, store.result ());
-    llvm::Value *arg = m_arguments[store.name ()];
-    store.stash_llvm (builder.CreateStore (arg_value, arg));
-  }
-
-  void
-  jit_convert_llvm::visit (jit_return& ret)
-  {
-    jit_value *res = ret.result ();
-
-    if (m_converting_function)
-      m_creating.do_return (builder, res->to_llvm (), false);
-    else
-      {
-        if (res)
-          builder.CreateRet (res->to_llvm ());
-        else
-          builder.CreateRetVoid ();
-      }
-  }
-
-  void
-  jit_convert_llvm::visit (jit_phi& phi)
-  {
-    // we might not have converted all incoming branches, so we don't
-    // set incoming branches now
-    llvm::PHINode *node = llvm::PHINode::Create (phi.type_llvm (),
-                                                 phi.argument_count ());
-    builder.Insert (node);
-    phi.stash_llvm (node);
-  }
-
-  void
-  jit_convert_llvm::visit (jit_variable&)
-  {
-    throw jit_fail_exception ("ERROR: SSA construction should remove all variables");
-  }
-
-  void
-  jit_convert_llvm::visit (jit_error_check& check)
-  {
-    llvm::Value *cond;
-
-    switch (check.check_variable ())
-      {
-      case jit_error_check::var_error_state:
-        cond = jit_typeinfo::insert_error_check (builder);
-        break;
-      case jit_error_check::var_interrupt:
-        cond = jit_typeinfo::insert_interrupt_check (builder);
-        break;
-      default:
-        panic_impossible ();
-      }
-
-    llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0),
-                                            check.successor_llvm (1));
-    check.stash_llvm (br);
-  }
-
-  void
-  jit_convert_llvm::visit (jit_assign& assign)
-  {
-    jit_value *new_value = assign.src ();
-    assign.stash_llvm (new_value->to_llvm ());
-
-    if (assign.artificial ())
-      return;
-
-    jit_value *overwrite = assign.overwrite ();
-    if (isa<jit_assign_base> (overwrite))
-      {
-        const jit_function& ol = jit_typeinfo::get_release (overwrite->type ());
-        if (ol.valid ())
-          ol.call (builder, overwrite);
-      }
-  }
-
-  void
-  jit_convert_llvm::visit (jit_argument&)
-  { }
-
-  void
-  jit_convert_llvm::visit (jit_magic_end& me)
-  {
-    const jit_function& ol = me.overload ();
-
-    jit_magic_end::context ctx = me.resolve_context ();
-    llvm::Value *ret = ol.call (builder, ctx.m_value, ctx.m_index,
-                                ctx.m_count);
-    me.stash_llvm (ret);
-  }
-
-  // -------------------- jit_infer --------------------
-  jit_infer::jit_infer (jit_factory& afactory, jit_block_list& ablocks,
-                        const variable_map& avmap)
-    : m_blocks (ablocks), m_factory (afactory), m_vmap (avmap) { }
-
-  void
-  jit_infer::infer (void)
-  {
-    construct_ssa ();
-
-    // initialize the worklist to instructions derived from constants
-    const std::list<jit_value *>& constants = m_factory.constants ();
-    for (auto iter = constants.begin (); iter != constants.end (); ++iter)
-      append_users (*iter);
-
-    // the entry block terminator may be a regular branch statement
-    if (entry_block ().terminator ())
-      push_worklist (entry_block ().terminator ());
-
-    // FIXME: Describe algorithm here
-    while (m_worklist.size ())
-      {
-        jit_instruction *next = m_worklist.front ();
-        m_worklist.pop_front ();
-        next->stash_in_worklist (false);
-
-        if (next->infer ())
-          {
-            // terminators need to be handles specially
-            if (jit_terminator *term = dynamic_cast<jit_terminator *> (next))
-              append_users_term (term);
-            else
-              append_users (next);
-          }
-      }
-
-    remove_dead ();
-    m_blocks.label ();
-    place_releases ();
-    simplify_phi ();
-  }
-
-  void
-  jit_infer::append_users (jit_value *v)
-  {
-    for (jit_use *use = v->first_use (); use; use = use->next ())
-      push_worklist (use->user ());
-  }
-
-  void
-  jit_infer::append_users_term (jit_terminator *term)
-  {
-    for (std::size_t i = 0; i < term->successor_count (); ++i)
-      {
-        if (term->alive (i))
-          {
-            jit_block *succ = term->successor (i);
-            for (auto iter = succ->begin ();
-                 iter != succ->end () && isa<jit_phi> (*iter); ++iter)
-              push_worklist (*iter);
-
-            jit_terminator *sterm = succ->terminator ();
-            if (sterm)
-              push_worklist (sterm);
-          }
-      }
-  }
-
-  void
-  jit_infer::construct_ssa (void)
-  {
-    m_blocks.label ();
-    final_block ().compute_idom (entry_block ());
-    entry_block ().compute_df ();
-    entry_block ().create_dom_tree ();
-
-    // insert phi nodes where needed, this is done on a per variable basis
-    for (auto iter = m_vmap.cbegin (); iter != m_vmap.cend (); ++iter)
-      {
-        jit_block::df_set visited, added_phi;
-        std::list<jit_block *> ssa_worklist;
-        iter->second->use_blocks (visited);
-        ssa_worklist.insert (ssa_worklist.begin (), visited.begin (),
-                             visited.end ());
-
-        while (ssa_worklist.size ())
-          {
-            jit_block *b = ssa_worklist.front ();
-            ssa_worklist.pop_front ();
-
-            for (auto diter = b->df_begin (); diter != b->df_end (); ++diter)
-              {
-                jit_block *dblock = *diter;
-                if (! added_phi.count (dblock))
-                  {
-                    jit_phi *phi = m_factory.create<jit_phi> (iter->second,
-                                                          dblock->use_count ());
-                    dblock->prepend (phi);
-                    added_phi.insert (dblock);
-                  }
-
-                if (! visited.count (dblock))
-                  {
-                    ssa_worklist.push_back (dblock);
-                    visited.insert (dblock);
-                  }
-              }
-          }
-      }
-
-    do_construct_ssa (entry_block (), entry_block ().visit_count ());
-  }
-
-  void
-  jit_infer::do_construct_ssa (jit_block& ablock, std::size_t avisit_count)
-  {
-    if (ablock.visited (avisit_count))
-      return;
-
-    // replace variables with their current SSA value
-    for (auto iter = ablock.begin (); iter != ablock.end (); ++iter)
-      {
-        jit_instruction *instr = *iter;
-        instr->construct_ssa ();
-        instr->push_variable ();
-      }
-
-    // finish phi nodes of successors
-    for (std::size_t i = 0; i < ablock.successor_count (); ++i)
-      {
-        jit_block *finish = ablock.successor (i);
-
-        for (auto  iter = finish->begin ();
-             iter != finish->end () && isa<jit_phi> (*iter);)
-          {
-            jit_phi *phi = static_cast<jit_phi *> (*iter);
-            jit_variable *var = phi->dest ();
-            ++iter;
-
-            if (var->has_top ())
-              phi->add_incoming (&ablock, var->top ());
-            else
-              {
-                // temporaries may have extraneous phi nodes which can be
-                // removed
-                assert (! phi->use_count ());
-                assert (var->name ().size () && var->name ()[0] == '#');
-                phi->remove ();
-              }
-          }
-      }
-
-    for (std::size_t i = 0; i < ablock.dom_successor_count (); ++i)
-      do_construct_ssa (*ablock.dom_successor (i), avisit_count);
-
-    ablock.pop_all ();
-  }
-
-  void
-  jit_infer::place_releases (void)
-  {
-    std::set<jit_value *> temporaries;
-    for (auto iter = m_blocks.begin (); iter != m_blocks.end (); ++iter)
-      {
-        jit_block& ablock = **iter;
-        if (ablock.id () != jit_block::NO_ID)
-          {
-            release_temp (ablock, temporaries);
-            release_dead_phi (ablock);
-          }
-      }
-  }
-
-  void
-  jit_infer::push_worklist (jit_instruction *instr)
-  {
-    if (! instr->in_worklist ())
-      {
-        instr->stash_in_worklist (true);
-        m_worklist.push_back (instr);
-      }
-  }
-
-  void
-  jit_infer::remove_dead ()
-  {
-    jit_block_list::iterator biter;
-    for (biter = m_blocks.begin (); biter != m_blocks.end (); ++biter)
-      {
-        jit_block *b = *biter;
-        if (b->alive ())
-          {
-            for (auto iter = b->begin ();
-                 iter != b->end () && isa<jit_phi> (*iter);)
-              {
-                jit_phi *phi = static_cast<jit_phi *> (*iter);
-                if (phi->prune ())
-                  iter = b->remove (iter);
-                else
-                  ++iter;
-              }
-          }
-      }
-
-    for (biter = m_blocks.begin (); biter != m_blocks.end ();)
-      {
-        jit_block *b = *biter;
-        if (b->alive ())
-          {
-            // FIXME: A special case for jit_error_check, if we generalize to
-            // we will need to change!
-            jit_terminator *term = b->terminator ();
-            if (term && term->successor_count () == 2 && ! term->alive (0))
-              {
-                jit_block *succ = term->successor (1);
-                term->remove ();
-                jit_branch *abreak = m_factory.create<jit_branch> (succ);
-                b->append (abreak);
-                abreak->infer ();
-              }
-
-            ++biter;
-          }
-        else
-          {
-            jit_terminator *term = b->terminator ();
-            if (term)
-              term->remove ();
-            biter = m_blocks.erase (biter);
-          }
-      }
-  }
-
-  void
-  jit_infer::release_dead_phi (jit_block& ablock)
-  {
-    auto iter = ablock.begin ();
-    while (iter != ablock.end () && isa<jit_phi> (*iter))
-      {
-        jit_phi *phi = static_cast<jit_phi *> (*iter);
-        ++iter;
-
-        jit_use *use = phi->first_use ();
-        if (phi->use_count () == 1 && isa<jit_assign> (use->user ()))
-          {
-            // instead of releasing on assign, release on all incoming
-            // branches, this can get rid of casts inside loops
-            for (std::size_t i = 0; i < phi->argument_count (); ++i)
-              {
-                jit_value *arg = phi->argument (i);
-                if (! arg->needs_release ())
-                  continue;
-
-                jit_block *inc = phi->incoming (i);
-                jit_block *split = inc->maybe_split (m_factory, m_blocks,
-                                                     ablock);
-                jit_terminator *term = split->terminator ();
-                jit_call *release
-                  = m_factory.create<jit_call> (jit_typeinfo::release, arg);
-                release->infer ();
-                split->insert_before (term, release);
-              }
-
-            phi->replace_with (0);
-            phi->remove ();
-          }
-      }
-  }
-
-  void
-  jit_infer::release_temp (jit_block& ablock, std::set<jit_value *>& temp)
-  {
-    for (auto iter = ablock.begin (); iter != ablock.end (); ++iter)
-      {
-        jit_instruction *instr = *iter;
-
-        // check for temporaries that require release and live across
-        // multiple blocks
-        if (instr->needs_release ())
-          {
-            jit_block *fu_block = instr->first_use_block ();
-            if (fu_block && fu_block != &ablock && instr->needs_release ())
-              temp.insert (instr);
-          }
-
-        if (isa<jit_call> (instr))
-          {
-            // place releases for temporary arguments
-            for (std::size_t i = 0; i < instr->argument_count (); ++i)
-              {
-                jit_value *arg = instr->argument (i);
-                if (! arg->needs_release ())
-                  continue;
-
-                jit_call *release
-                  = m_factory.create<jit_call> (&jit_typeinfo::release, arg);
-                release->infer ();
-                ablock.insert_after (iter, release);
-                ++iter;
-                temp.erase (arg);
-              }
-          }
-      }
-
-    if (! temp.size () || ! isa<jit_error_check> (ablock.terminator ()))
-      return;
-
-    // FIXME: If we support try/catch or unwind_protect final_block
-    //        may not be the destination
-    jit_block *split = ablock.maybe_split (m_factory, m_blocks,
-                                           final_block ());
-    jit_terminator *term = split->terminator ();
-    for (auto iter = temp.cbegin (); iter != temp.cend (); ++iter)
-      {
-        jit_value *value = *iter;
-        jit_call *release
-          = m_factory.create<jit_call> (&jit_typeinfo::release, value);
-        split->insert_before (term, release);
-        release->infer ();
-      }
-  }
-
-  void
-  jit_infer::simplify_phi (void)
-  {
-    for (auto biter = m_blocks.begin (); biter != m_blocks.end (); ++biter)
-      {
-        jit_block &ablock = **biter;
-        for (auto iter = ablock.begin ();
-             iter != ablock.end () && isa<jit_phi> (*iter); ++iter)
-          simplify_phi (*static_cast<jit_phi *> (*iter));
-      }
-  }
-
-  void
-  jit_infer::simplify_phi (jit_phi& phi)
-  {
-    jit_block& pblock = *phi.parent ();
-    const jit_operation& cast_fn = jit_typeinfo::cast (phi.type ());
-    jit_variable *dest = phi.dest ();
-    for (std::size_t i = 0; i < phi.argument_count (); ++i)
-      {
-        jit_value *arg = phi.argument (i);
-        if (arg->type () != phi.type ())
-          {
-            jit_block *pred = phi.incoming (i);
-            jit_block *split = pred->maybe_split (m_factory, m_blocks, pblock);
-            jit_terminator *term = split->terminator ();
-            jit_instruction *cast = m_factory.create<jit_call> (cast_fn, arg);
-            jit_assign *assign = m_factory.create<jit_assign> (dest, cast);
-
-            split->insert_before (term, cast);
-            split->insert_before (term, assign);
-            cast->infer ();
-            assign->infer ();
-            phi.stash_argument (i, assign);
-          }
-      }
-  }
-
-
-  // ---------------- jit_memory_manager ------------------
-
-  // A simple memory manager for our LLVM engines,
-  // based on LLVM's Kaleidoscope example
-
-  class jit_memory_manager : public llvm::SectionMemoryManager
-  {
-    jit_memory_manager (const jit_memory_manager&) = delete;
-    void operator= (const jit_memory_manager&) = delete;
-  public:
-    jit_memory_manager () { }
-    virtual ~jit_memory_manager () { }
-
-    // The Kaleidoscope example in LLVM 3.8 indicates that
-    // getPointerToNamedFunction has to be overloaded, but actually it is
-    // getSymbolAddress that must be overloaded.
-    virtual uint64_t getSymbolAddress (const std::string &name);
-
-    // Is it still useful to overload getPointerToNamedFunction to support
-    // some older version of LLVM?  Are there others virtual functions
-    // that must be overloaded?
-    virtual void* getPointerToNamedFunction (const std::string& name, bool
-                                             abort_on_failure);
-  };
-
-  void*
-  jit_memory_manager::getPointerToNamedFunction (const std::string& name,
-                                                 bool abort_on_failure)
-  {
-    // Try the standard symbol resolution first, but ask it not to abort
-    void *pfn = llvm::RTDyldMemoryManager::getPointerToNamedFunction (name,
-                                                                      false);
-    if (pfn)
-      return pfn;
-
-    pfn = tree_jit::getPointerToNamedFunction (name);
-    if ((pfn == nullptr) && abort_on_failure)
-      llvm::report_fatal_error ("Program used external function '" + name +
-                                "' which could not be resolved!");
-    return pfn;
-  }
-
-  uint64_t
-  jit_memory_manager::getSymbolAddress (const std::string &name)
-  {
-    uint64_t addr = llvm::SectionMemoryManager::getSymbolAddress (name);
-    if (addr)
-      return addr;
-
-    addr = tree_jit::getSymbolAddress (name);
-    if (addr == 0)
-      llvm::report_fatal_error ("Program used extern function '" + name +
-                                "' which could not be resolved!");
-
-    return addr;
-  }
-
-
-  // -------------------- tree_jit --------------------
-
-  bool tree_jit::initialized = false;
-
-  llvm::LLVMContext tree_jit::llvm_context;
-
-  int tree_jit::next_forloop_number = 0;
-  int tree_jit::next_function_number = 0;
-  int tree_jit::next_module_number = 0;
-
-  tree_jit::tree_jit (void)
-    : target_machine (nullptr)
-  {
-    // target_machine will be truly initialized by tree_jit::do_initialize ()
-  }
-
-  tree_jit::~tree_jit (void)
-  {
-    delete target_machine;
-  }
-
-  tree_jit&
-  tree_jit::instance (void)
-  {
-    static tree_jit ret;  // singleton instance of tree_jit
-
-    if (! initialized)
-      // Try to initialize the singleton instance
-      ret.do_initialize ();
-
-    return ret;
-  }
-
-  jit::EngineOwner
-  tree_jit::create_new_engine (jit::ModuleOwner module_owner)
-  {
-    std::string err;
-
-    llvm::ExecutionEngine *e = llvm::EngineBuilder (std::move (module_owner))
-      .setErrorStr (&err)
-      .setMCJITMemoryManager(llvm::make_unique<jit_memory_manager> ())
-      .create ();
-
-    // Note: in some versions of LLVM, we should call .setUseMCJIT (true)
-    // before .create () ?
-    // FIXME: autconf this
-
-    if (e == nullptr)
-      error ("failed to create JIT engine: %s", err.c_str ());
-
-    return jit::EngineOwner (e);
-  }
-
-  void
-  tree_jit::do_register_jit_module (jit_module* jm)
-  {
-    jm_list.push_back (jm);
-  }
-
-  void
-  tree_jit::do_unregister_jit_module (jit_module* jm)
-  {
-    jm_list.remove (jm);
-  }
-
-  void*
-  tree_jit::do_getPointerToNamedFunction (const std::string &name) const
-  {
-    std::list<jit_module*>::const_iterator it;
-
-    for (it = jm_list.begin (); it != jm_list.end (); it++)
-      {
-        uint64_t addr = (*it)->getFunctionAddress (name);
-
-        if (addr)
-          return reinterpret_cast<void*> (addr);
-      }
-
-    return nullptr;
-  }
-
-  uint64_t
-  tree_jit::do_getSymbolAddress(const std::string &name) const
-  {
-    std::list<jit_module*>::const_iterator it;
-
-    for (it = jm_list.begin (); it != jm_list.end (); it++)
-      {
-        uint64_t addr = (*it)->getFunctionAddress (name);
-
-        if (addr)
-          return addr;
-      }
-
-    return 0;
-  }
-
-  bool
-  tree_jit::do_initialize (void)
-  {
-    if (initialized)
-      return true;
-
-    llvm::InitializeNativeTarget ();
-    llvm::InitializeNativeTargetAsmPrinter ();
-    llvm::InitializeNativeTargetAsmParser ();
-    // FIXME: Check that these three initializations succeed
-
-    if (target_machine == nullptr)
-      {
-        target_machine = llvm::EngineBuilder ().selectTarget ();
-        if (target_machine == nullptr)
-          return false;
-      }
-
-    return (initialized = true);
-  }
-
-  jit::ModuleOwner
-  tree_jit::open_new_module (const std::string& module_name)
-  {
-    return instance ().do_open_new_module (module_name);
-  }
-
-  jit::ModuleOwner
-  tree_jit::do_open_new_module (const std::string& module_name) const
-  {
-    if (! initialized)
-      return nullptr;
-
-    jit::ModuleOwner m (new llvm::Module (module_name, context));
-
-
-    if (m != nullptr)
-      m->setDataLayout (target_machine->createDataLayout ());
-
-    return m;
-  }
-
-  bool
-  tree_jit::do_execute (tree_simple_for_command& cmd,
-                        const octave_value& bounds)
-  {
-    std::size_t tc = trip_count (bounds);
-    if (! tc || ! initialized || ! enabled ())
-      return false;
-
-    jit_info::vmap extra_vars;
-    extra_vars["#for_bounds0"] = &bounds;
-
-    jit_info *info = cmd.get_info ();
-
-    if (! info || ! info->match (extra_vars))
-      {
-        if (tc < static_cast<std::size_t> (Vjit_startcnt))
-          return false;
-
-        delete info;
-
-        info = new jit_info (cmd, bounds);
-
-        cmd.stash_info (info);
-      }
-
-    return info->execute (extra_vars);
-  }
-
-  bool
-  tree_jit::do_execute (tree_while_command& cmd)
-  {
-    if (! initialized || ! enabled ())
-      return false;
-
-    jit_info *info = cmd.get_info ();
-    if (! info || ! info->match ())
-      {
-        delete info;
-        info = new jit_info (cmd);
-        cmd.stash_info (info);
-      }
-
-    return info->execute ();
-  }
-
-  bool
-  tree_jit::do_execute (octave_user_function& fcn,
-                        const octave_value_list& args,
-                        octave_value_list& retval)
-  {
-    if (! initialized || ! enabled ())
-      return false;
-
-    jit_function_info *info = fcn.get_info ();
-    if (! info || ! info->match (args))
-      {
-        delete info;
-        info = new jit_function_info (fcn, args);
-        fcn.stash_info (info);
-      }
-
-    return info->execute (args, retval);
-  }
-
-  bool
-  tree_jit::enabled (void)
-  {
-    bp_table& bptab = __get_bp_table__ ("tree_jit::enabled");
-
-    // Ideally, we should only disable JIT if there is a breakpoint in the code
-    // we are about to run.  However, we can't figure this out in O(1) time, so
-    // we conservatively check for the existence of any breakpoints.
-    return (Vjit_enable && ! bptab.have_breakpoints ()
-            && ! Vdebug_on_interrupt && ! Vdebug_on_error);
-  }
-
-  std::size_t
-  tree_jit::trip_count (const octave_value& bounds) const
-  {
-    if (bounds.is_range ())
-      {
-        range<double> rng = bounds.range_value ();
-        return rng.numel ();
-      }
-
-    // unsupported type
-    return 0;
-  }
-
-
-  // -------------------- jit_module --------------------
-
-  jit_module::jit_module (const std::string& module_name)
-    : m_module (nullptr), m_engine (nullptr)
-  {
-    jit::ModuleOwner module_owner = tree_jit::open_new_module (module_name);
-    // FIXME: what if this fails? exception?
-
-    // Get a pointer to the module before ownership is transferred to engine
-    m_module = module_owner.get ();
-
-    jit::EngineOwner engine_owner = std::move
-      (tree_jit::create_new_engine (std::move (module_owner)));
-    // FIXME: what if this fails? exception?
-
-    // TODO?: Consider creating the engine just before jitting
-
-    // We take responsibility for deleting the engine
-    m_engine = engine_owner.get ();
-    engine_owner.release ();
-
-    tree_jit::register_jit_module (this);
-  }
-
-  jit_module::~jit_module ()
-  {
-    tree_jit::unregister_jit_module (this);
-
-    delete m_engine;
-  }
-
-  // Create an LLVM function in the module, with external linkage
-  llvm::Function*
-  jit_module::create_llvm_function (llvm::FunctionType *ftype,
-                                    const llvm::Twine &name) const
-  {
-    // we mark all functinos as external linkage because this prevents
-    // llvm from getting rid of always inline functions
-
-    return llvm::Function::Create (ftype, llvm::Function::ExternalLinkage,
-                                   name, m_module);
-  }
-
-  // Create or insert an LLVM Function declaration for an intrinsic and return
-  // it
-  llvm::Function*
-  jit_module::get_intrinsic_declaration (std::size_t id,
-                                         std::vector<llvm::Type*> types) const
-  {
-    return llvm::Intrinsic::getDeclaration
-      (m_module, static_cast<llvm::Intrinsic::ID> (id), types);
-  }
-
-  // Create a global in the module
-  llvm::GlobalVariable*
-  jit_module::create_global_variable (llvm::Type *type, bool is_constant,
-                                      const llvm::Twine& name) const
-  {
-    return new llvm::GlobalVariable (*m_module, type, is_constant,
-                                     llvm::GlobalValue::ExternalLinkage,
-                                     nullptr, name);
-  }
-
-  void
-  jit_module::do_add_global_mapping (const llvm::GlobalValue* gv, void* p) const
-  {
-    assert (gv);
-    m_engine->addGlobalMapping (gv, p);
-  }
-
-  // Return the address of the specified function.
-  uint64_t
-  jit_module::getFunctionAddress (const std::string &name) const
-  {
-    return m_engine->getFunctionAddress (name);
-  }
-
-  void
-  jit_module::optimize (llvm::Function *fn) const
-  {
-    if (Vdebug_jit)
-      llvm::verifyModule (*m_module);
-
-    // DOCUMENT-ME: Why do we need two separate pass managers?
-
-    jit::PassManager *module_pass_manager = new jit::PassManager ();
-    jit::FunctionPassManager *pass_manager = new jit::FunctionPassManager (m_module);
-
-#if defined (LLVM_HAS_CREATEALWAYSINLINERPASS)
-    // This pass has been removed from LLVM's C++ API after 3.9.0
-    // FIXME: Provide a meaningful replacement instead of simply skipping it?
-    module_pass_manager->add (llvm::createAlwaysInlinerPass ());
-#endif
-
-    // In 3.6, a pass was inserted in the pipeline to make the DataLayout accessible:
-    //    MyPassManager->add(new DataLayoutPass(MyTargetMachine->getDataLayout()));
-    // In 3.7, you don’t need a pass, you set the DataLayout on the Module:
-    //    MyModule->setDataLayout(MyTargetMachine->createDataLayout());
-    //
-    // FIXME: autoconf to support <= 3.6
-    //
-    // #if defined (HAVE_LLVM_DATALAYOUT)
-    //   pass_manager->add (new llvm::DataLayout (*m_engine->getDataLayout ()));
-    // #else
-    //   // For very old LLVM releases ???
-    //   pass_manager->add (new llvm::TargetData (*m_engine->getTargetData ()));
-    // #endif
-
-    // DOCUMENT-ME: What does each of these passes actually do?
-
-    pass_manager->add (llvm::createCFGSimplificationPass ());
-
-#if defined (HAVE_LLVM_ANALYSIS_BASICALIASANALYSIS_H)
-    pass_manager->add (llvm::createBasicAAWrapperPass ());
-#else
-    pass_manager->add (llvm::createBasicAliasAnalysisPass ());
-#endif
-
-    pass_manager->add (llvm::createPromoteMemoryToRegisterPass ());
-    pass_manager->add (llvm::createInstructionCombiningPass ());
-    pass_manager->add (llvm::createReassociatePass ());
-    pass_manager->add (llvm::createGVNPass ());
-    pass_manager->add (llvm::createCFGSimplificationPass ());
-    pass_manager->doInitialization ();
-
-    module_pass_manager->run (*m_module);
-    pass_manager->run (*fn);
-
-    delete module_pass_manager;
-    delete pass_manager;
-
-    if (Vdebug_jit)
-      {
-        // This should be OK in LLVM 3.6 -- 3.8 (and later ?)
-        std::error_code ec;
-        llvm::raw_fd_ostream fout ("test.bc", ec, llvm::sys::fs::F_None);
-
-        //      std::string error;
-        //#if defined (RAW_FD_OSTREAM_ARG_IS_LLVM_SYS_FS)
-        //      llvm::raw_fd_ostream fout ("test.bc", error, llvm::sys::fs::F_Binary);
-        //#else
-        //      llvm::raw_fd_ostream fout ("test.bc", error, llvm::raw_fd_ostream::F_Binary);
-        //#endif
-
-        llvm::WriteBitcodeToFile (m_module, fout);
-      }
-  }
-
-  void
-  jit_module::finalizeObject (void)
-  {
-    m_engine->finalizeObject ();
-  }
-
-
-  // -------------------- jit_function_info --------------------
-  jit_function_info::jit_function_info (octave_user_function& fcn,
-                                        const octave_value_list& ov_args)
-    : m_llvm_function_name (""),
-      m_function (nullptr),
-      m_argument_types (ov_args.length ())
-  {
-    std::size_t nargs = ov_args.length ();
-    for (std::size_t i = 0; i < nargs; ++i)
-      m_argument_types[i] = jit_typeinfo::type_of (ov_args(i));
-
-    jit_function raw_fn;
-    jit_function wrapper;
-
-    try
-      {
-        jit_convert conv (fcn, m_argument_types);
-        jit_infer infer (conv.get_factory (), conv.get_blocks (),
-                         conv.get_variable_map ());
-        infer.infer ();
-
-        if (Vdebug_jit)
-          {
-            jit_block_list& blocks = infer.get_blocks ();
-            blocks.label ();
-            octave_stdout << "-------------------- Compiling function ";
-            octave_stdout << "--------------------\n";
-
-            tree_print_code tpc (octave_stdout);
-            tpc.visit_octave_user_function_header (fcn);
-            tpc.visit_statement_list (*fcn.body ());
-            tpc.visit_octave_user_function_trailer (fcn);
-            blocks.print (octave_stdout, "octave jit ir");
-          }
-
-        jit_factory& factory = conv.get_factory ();
-        jit_convert_llvm to_llvm;
-        raw_fn = to_llvm.convert_function (*this, infer.get_blocks (),
-                                           factory.constants (), fcn,
-                                           m_argument_types);
-
-        if (Vdebug_jit)
-          {
-            octave_stdout << "-------------------- raw function ";
-            octave_stdout << "--------------------\n";
-            octave_stdout << *raw_fn.to_llvm () << std::endl;
-            llvm::verifyFunction (*raw_fn.to_llvm ());
-          }
-
-        m_llvm_function_name = fcn.name () + "_wrapper";
-        jit_type *any_t = jit_typeinfo::get_any ();
-        std::vector<jit_type *> wrapper_args (1, jit_typeinfo::get_any_ptr ());
-        wrapper = jit_function (this, jit_convention::internal,
-                                m_llvm_function_name, any_t, wrapper_args);
-
-        llvm::BasicBlock *wrapper_body = wrapper.new_block ();
-        builder.SetInsertPoint (wrapper_body);
-
-        llvm::Value *wrapper_arg = wrapper.argument (builder, 0);
-        std::vector<llvm::Value *> raw_args (nargs);
-        for (std::size_t i = 0; i < nargs; ++i)
-          {
-            llvm::Value *arg;
-            // LLVM <= 3.6
-            // arg = builder.CreateConstInBoundsGEP1_32 (wrapper_arg, i);
-            // LLVM >= 3.7
-            arg = builder.CreateConstInBoundsGEP1_32 (any_t->to_llvm (),
-                                                      wrapper_arg, i);
-
-            arg = builder.CreateLoad (arg);
-
-            jit_type *arg_type = m_argument_types[i];
-            const jit_function& cast = jit_typeinfo::cast (arg_type, any_t);
-            raw_args[i] = cast.call (builder, arg);
-          }
-
-        llvm::Value *result = raw_fn.call (builder, raw_args);
-        if (raw_fn.result ())
-          {
-            jit_type *raw_result_t = raw_fn.result ();
-            const jit_function& cast = jit_typeinfo::cast (any_t,
-                                                           raw_result_t);
-            result = cast.call (builder, result);
-          }
-        else
-          {
-            llvm::Value *zero = builder.getInt32 (0);
-            result = builder.CreateBitCast (zero, any_t->to_llvm ());
-          }
-
-        wrapper.do_return (builder, result);
-
-        llvm::Function *llvm_function = wrapper.to_llvm ();
-        optimize (llvm_function);
-
-        if (Vdebug_jit)
-          {
-            octave_stdout << "-------------------- optimized and wrapped ";
-            octave_stdout << "--------------------\n";
-            octave_stdout << *llvm_function << std::endl;
-            llvm::verifyFunction (*llvm_function);
-          }
-
-        finalizeObject ();
-
-        uint64_t void_fn = getFunctionAddress (m_llvm_function_name);
-
-        if (void_fn == 0)
-          {
-            llvm_function->eraseFromParent ();
-            llvm_function = nullptr;
-            m_function = nullptr;
-          }
-        else
-          {
-            m_function = reinterpret_cast<jited_function> (void_fn);
-          }
-      }
-    catch (const jit_fail_exception& jfe)
-      {
-        m_argument_types.clear ();
-
-        if (Vdebug_jit)
-          {
-            if (jfe.known ())
-              octave_stdout << "jit fail: " << jfe.what () << std::endl;
-          }
-
-        Vjit_failcnt++;
-
-        wrapper.erase ();
-        raw_fn.erase ();
-      }
-  }
-
-  bool
-  jit_function_info::execute (const octave_value_list& ov_args,
-                              octave_value_list& retval) const
-  {
-    if (! m_function)
-      return false;
-
-    // FIXME: figure out a way to delete ov_args so we avoid duplicating
-    // refcount
-    std::size_t nargs = ov_args.length ();
-    std::vector<octave_base_value *> args (nargs);
-    for (std::size_t i = 0; i < nargs; ++i)
-      {
-        octave_base_value *obv = ov_args(i).internal_rep ();
-        obv->grab ();
-        args[i] = obv;
-      }
-
-    octave_base_value *ret = m_function (&args[0]);
-    if (ret)
-      retval(0) = octave_value (ret);
-
-    octave_quit ();
-
-    return true;
-  }
-
-  bool
-  jit_function_info::match (const octave_value_list& ov_args) const
-  {
-    if (! m_function)
-      return true;
-
-    std::size_t nargs = ov_args.length ();
-    if (nargs != m_argument_types.size ())
-      return false;
-
-    for (std::size_t i = 0; i < nargs; ++i)
-      if (jit_typeinfo::type_of (ov_args(i)) != m_argument_types[i])
-        return false;
-
-    return true;
-  }
-
-
-  // -------------------- jit_info --------------------
-  jit_info::jit_info (tree& tee)
-    : m_llvm_function_name (tree_jit::generate_unique_function_name ()),
-      m_function (nullptr)
-  {
-    compile (tee);
-  }
-
-  jit_info::jit_info (tree& tee, const octave_value& for_bounds)
-    : m_llvm_function_name (tree_jit::generate_unique_function_name ()),
-      m_function (nullptr)
-  {
-    compile (tee, jit_typeinfo::type_of (for_bounds));
-  }
-
-  jit_info::jit_info (tree_simple_for_command& tee,
-                      const octave_value& for_bounds)
-    : m_llvm_function_name (tree_jit::generate_unique_forloop_name ()),
-      m_function (nullptr)
-  {
-    compile (tee, jit_typeinfo::type_of (for_bounds));
-  }
-
-  bool
-  jit_info::execute (const vmap& extra_vars) const
-  {
-    if (! m_function)
-      return false;
-
-    std::vector<octave_base_value *> real_arguments (m_arguments.size ());
-    for (std::size_t i = 0; i < m_arguments.size (); ++i)
-      {
-        if (m_arguments[i].second)
-          {
-            octave_value current = find (extra_vars, m_arguments[i].first);
-            octave_base_value *obv = current.internal_rep ();
-
-            obv->grab ();
-
-            real_arguments[i] = obv;
-          }
-      }
-
-    m_function (&real_arguments[0]);
-
-    symbol_scope scope = __require_current_scope__ ("jit_info::execute");
-
-    for (std::size_t i = 0; i < m_arguments.size (); ++i)
-      {
-        const std::string& name = m_arguments[i].first;
-
-        // do not store for loop bounds temporary
-        if (name.size () && name[0] != '#')
-          scope.assign (m_arguments[i].first, real_arguments[i]);
-      }
-
-    octave_quit ();
-
-    return true;
-  }
-
-  bool
-  jit_info::match (const vmap& extra_vars) const
-  {
-    if (! m_function)
-      return true;
-
-    for (std::size_t i = 0; i < m_bounds.size (); ++i)
-      {
-        const std::string& arg_name = m_bounds[i].second;
-        octave_value value = find (extra_vars, arg_name);
-        jit_type *type = jit_typeinfo::type_of (value);
-
-        // FIXME: Check for a parent relationship
-        if (type != m_bounds[i].first)
-          return false;
-      }
-
-    return true;
-  }
-
-  void
-  jit_info::compile (tree& tee, jit_type *for_bounds)
-  {
-    llvm::Function * llvm_function = nullptr;
-
-    try
-      {
-        jit_convert conv (tee, for_bounds);
-        jit_infer infer (conv.get_factory (), conv.get_blocks (),
-                         conv.get_variable_map ());
-
-        infer.infer ();
-
-        if (Vdebug_jit)
-          {
-            jit_block_list& blocks = infer.get_blocks ();
-            blocks.label ();
-            octave_stdout << "-------------------- Compiling tree --------------------\n";
-            octave_stdout << tee.str_print_code () << std::endl;
-            blocks.print (octave_stdout, "octave jit ir");
-          }
-
-        jit_factory& factory = conv.get_factory ();
-        jit_convert_llvm to_llvm;
-
-        llvm_function = to_llvm.convert_loop (*this, infer.get_blocks (),
-                                              factory.constants (),
-                                              m_llvm_function_name);
-
-        m_arguments = to_llvm.get_arguments ();
-
-        m_bounds = conv.get_bounds ();
-      }
-    catch (const jit_fail_exception& jfe)
-      {
-        if (Vdebug_jit)
-          {
-            if (jfe.known ())
-              octave_stdout << "jit fail: " << jfe.what () << std::endl;
-          }
-
-        Vjit_failcnt++;
-      }
-
-    if (llvm_function)
-      {
-        if (Vdebug_jit)
-          {
-            octave_stdout << "-------------------- llvm ir --------------------";
-            octave_stdout << *llvm_function << std::endl;
-            llvm::verifyFunction (*llvm_function);
-          }
-
-        optimize (llvm_function);
-
-        if (Vdebug_jit)
-          {
-            octave_stdout << "-------------------- optimized llvm ir "
-                      << "--------------------\n";
-            octave_stdout << *llvm_function << std::endl;
-          }
-
-        finalizeObject ();
-
-        uint64_t void_fn = getFunctionAddress (m_llvm_function_name);
-
-        if (void_fn == 0)
-          {
-            llvm_function->eraseFromParent ();
-            llvm_function = nullptr;
-            m_function = nullptr;
-          }
-        else
-          {
-            m_function = reinterpret_cast<jited_function> (void_fn);
-          }
-      }
-  }
-
-  octave_value
-  jit_info::find (const vmap& extra_vars, const std::string& vname) const
-  {
-    vmap::const_iterator iter = extra_vars.find (vname);
-
-    if (iter == extra_vars.end ())
-      {
-        symbol_scope scope = __require_current_scope__ ("jit_convert::find");
-
-        return scope.varval (vname);
-      }
-    else
-      return *iter->second;
-  }
-}
-
-#endif
-
-DEFUN (jit_failcnt, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} jit_failcnt ()
-@deftypefnx {} {@var{old_val} =} jit_failcnt (@var{new_val})
-@deftypefnx {} {} jit_failcnt (@var{new_val}, "local")
-Query or set the internal variable that counts the number of JIT fail
-exceptions for Octave's JIT compiler.
-
-When called from inside a function with the @qcode{"local"} option, the
-variable is changed locally for the function and any subroutines it calls.
-The original variable value is restored when exiting the function.
-@seealso{jit_enable, jit_startcnt, debug_jit}
-@end deftypefn */)
-{
-#if defined (HAVE_LLVM)
-  return SET_INTERNAL_VARIABLE (jit_failcnt);
-#else
-  octave_unused_parameter (args);
-  octave_unused_parameter (nargout);
-  warn_disabled_feature ("jit_failcnt", "JIT compiling");
-  return ovl ();
-#endif
-}
-
-DEFUN (debug_jit, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} debug_jit ()
-@deftypefnx {} {@var{old_val} =} debug_jit (@var{new_val})
-@deftypefnx {} {} debug_jit (@var{new_val}, "local")
-Query or set the internal variable that determines whether
-debugging/tracing is enabled for Octave's JIT compiler.
-
-When called from inside a function with the @qcode{"local"} option, the
-variable is changed locally for the function and any subroutines it calls.
-The original variable value is restored when exiting the function.
-@seealso{jit_enable, jit_startcnt}
-@end deftypefn */)
-{
-#if defined (HAVE_LLVM)
-  return SET_INTERNAL_VARIABLE (debug_jit);
-#else
-  octave_unused_parameter (args);
-  octave_unused_parameter (nargout);
-  warn_disabled_feature ("debug_jit", "JIT");
-  return ovl ();
-#endif
-}
-
-DEFUN (jit_enable, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} jit_enable ()
-@deftypefnx {} {@var{old_val} =} jit_enable (@var{new_val})
-@deftypefnx {} {} jit_enable (@var{new_val}, "local")
-Query or set the internal variable that enables Octave's JIT compiler.
-
-When called from inside a function with the @qcode{"local"} option, the
-variable is changed locally for the function and any subroutines it calls.
-The original variable value is restored when exiting the function.
-@seealso{jit_startcnt, debug_jit}
-@end deftypefn */)
-{
-#if defined (HAVE_LLVM)
-  return SET_INTERNAL_VARIABLE (jit_enable);
-#else
-  octave_unused_parameter (args);
-  octave_unused_parameter (nargout);
-  warn_disabled_feature ("jit_enable", "JIT");
-  return ovl ();
-#endif
-}
-
-DEFUN (jit_startcnt, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} jit_startcnt ()
-@deftypefnx {} {@var{old_val} =} jit_startcnt (@var{new_val})
-@deftypefnx {} {} jit_startcnt (@var{new_val}, "local")
-Query or set the internal variable that determines whether JIT compilation
-will take place for a specific loop.
-
-Because compilation is a costly operation it does not make sense to employ
-JIT when the loop count is low.  By default only loops with greater than
-1000 iterations will be accelerated.
-
-When called from inside a function with the @qcode{"local"} option, the
-variable is changed locally for the function and any subroutines it calls.
-The original variable value is restored when exiting the function.
-@seealso{jit_enable, jit_failcnt, debug_jit}
-@end deftypefn */)
-{
-#if defined (HAVE_LLVM)
-  return SET_INTERNAL_VARIABLE_WITH_LIMITS (jit_startcnt, 1,
-                                            std::numeric_limits<int>::max ());
-#else
-  octave_unused_parameter (args);
-  octave_unused_parameter (nargout);
-  warn_disabled_feature ("jit_startcnt", "JIT");
-  return ovl ();
-#endif
-}
--- a/libinterp/parse-tree/pt-jit.h	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,645 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-#if ! defined (octave_pt_jit_h)
-#define octave_pt_jit_h 1
-
-#include "octave-config.h"
-
-#if defined (HAVE_LLVM)
-
-#include "jit-util.h"
-#include "jit-typeinfo.h"
-#include "jit-ir.h"
-#include "pt-walk.h"
-#include "symscope.h"
-
-// octave_value_list is not (yet) in the octave namespace
-class octave_value_list;
-
-namespace octave
-{
-  namespace jit
-  {
-    typedef std::unique_ptr<llvm::Module> ModuleOwner;
-    typedef std::unique_ptr<llvm::ExecutionEngine> EngineOwner;
-  }
-
-  // Convert from the parse tree (AST) to the low level Octave IR.
-  class
-  jit_convert : public tree_walker
-  {
-  public:
-
-    typedef std::pair<jit_type *, std::string> type_bound;
-    typedef std::vector<type_bound> type_bound_vector;
-    typedef std::map<std::string, jit_variable *> variable_map;
-
-    jit_convert (tree& tee, jit_type *for_bounds = nullptr);
-
-    jit_convert (octave_user_function& fcn, const std::vector<jit_type *>& args);
-
-    template <typename ...Args>
-    jit_call * create_checked (const Args&... args)
-    {
-      jit_call *ret = m_factory.create<jit_call> (args...);
-      return create_checked_impl (ret);
-    }
-
-    jit_block_list& get_blocks (void) { return m_blocks; }
-
-    const type_bound_vector& get_bounds (void) const { return m_bounds; }
-
-    jit_factory& get_factory (void) { return m_factory; }
-
-    llvm::Function *get_function (void) const { return m_function; }
-
-    const variable_map& get_variable_map (void) const { return m_vmap; }
-
-    void visit_anon_fcn_handle (tree_anon_fcn_handle&);
-
-    void visit_argument_list (tree_argument_list&);
-
-    void visit_binary_expression (tree_binary_expression&);
-
-    void visit_boolean_expression (tree_boolean_expression&);
-
-    void visit_break_command (tree_break_command&);
-
-    void visit_colon_expression (tree_colon_expression&);
-
-    void visit_continue_command (tree_continue_command&);
-
-    void visit_decl_command (tree_decl_command&);
-
-    void visit_decl_init_list (tree_decl_init_list&);
-
-    void visit_decl_elt (tree_decl_elt&);
-
-    void visit_simple_for_command (tree_simple_for_command&);
-
-    void visit_complex_for_command (tree_complex_for_command&);
-
-    void visit_octave_user_script (octave_user_script&);
-
-    void visit_octave_user_function (octave_user_function&);
-
-    void visit_octave_user_function_header (octave_user_function&);
-
-    void visit_octave_user_function_trailer (octave_user_function&);
-
-    void visit_function_def (tree_function_def&);
-
-    void visit_identifier (tree_identifier&);
-
-    void visit_if_clause (tree_if_clause&);
-
-    void visit_if_command (tree_if_command&);
-
-    void visit_if_command_list (tree_if_command_list&);
-
-    void visit_index_expression (tree_index_expression&);
-
-    void visit_matrix (tree_matrix&);
-
-    void visit_cell (tree_cell&);
-
-    void visit_multi_assignment (tree_multi_assignment&);
-
-    void visit_no_op_command (tree_no_op_command&);
-
-    void visit_constant (tree_constant&);
-
-    void visit_fcn_handle (tree_fcn_handle&);
-
-    void visit_parameter_list (tree_parameter_list&);
-
-    void visit_postfix_expression (tree_postfix_expression&);
-
-    void visit_prefix_expression (tree_prefix_expression&);
-
-    void visit_return_command (tree_return_command&);
-
-    void visit_simple_assignment (tree_simple_assignment&);
-
-    void visit_statement (tree_statement&);
-
-    void visit_statement_list (tree_statement_list&);
-
-    void visit_switch_case (tree_switch_case&);
-
-    void visit_switch_case_list (tree_switch_case_list&);
-
-    void visit_switch_command (tree_switch_command&);
-
-    void visit_try_catch_command (tree_try_catch_command&);
-
-    void visit_unwind_protect_command (tree_unwind_protect_command&);
-
-    void visit_while_command (tree_while_command&);
-
-    void visit_do_until_command (tree_do_until_command&);
-
-  private:
-
-    std::vector<std::pair<std::string, bool>> m_arguments;
-    type_bound_vector m_bounds;
-
-    bool m_converting_function;
-
-    // the scope of the function we are converting, or the current scope
-    symbol_scope m_scope;
-
-    jit_factory m_factory;
-
-    // used instead of return values from visit_* functions
-    jit_value *m_result;
-
-    jit_block *m_entry_block;
-
-    jit_block *m_final_block;
-
-    jit_block *m_block;
-
-    llvm::Function *m_function;
-
-    jit_block_list m_blocks;
-
-    std::vector<jit_magic_end::context> m_end_context;
-
-    std::size_t m_iterator_count;
-    std::size_t m_for_bounds_count;
-    std::size_t m_short_count;
-
-    variable_map m_vmap;
-
-    void initialize (const symbol_scope& s);
-
-    jit_call * create_checked_impl (jit_call *ret);
-
-    // get an existing vairable.  If the variable does not exist, it will not be
-    // created
-    jit_variable * find_variable (const std::string& vname) const;
-
-    // get a variable, create it if it does not exist.  The type will default to
-    // the variable's current type in the symbol table.
-    jit_variable * get_variable (const std::string& vname);
-
-    // create a variable of the given name and given type.  Will also insert an
-    // extract statement
-    jit_variable * create_variable (const std::string& vname, jit_type *type,
-                                    bool isarg = true);
-
-    // The name of the next for loop iterator.  If inc is false, then the
-    // iterator counter will not be incremented.
-    std::string next_iterator (bool inc = true)
-    { return next_name ("#iter", m_iterator_count, inc); }
-
-    std::string next_for_bounds (bool inc = true)
-    { return next_name ("#for_bounds", m_for_bounds_count, inc); }
-
-    std::string next_shortcircut_result (bool inc = true)
-    { return next_name ("#shortcircut_result", m_short_count, inc); }
-
-    std::string next_name (const char *prefix, std::size_t& count, bool inc);
-
-    jit_instruction * resolve (tree_index_expression& exp,
-                               jit_value *extra_arg = nullptr, bool lhs = false);
-
-    jit_value * do_assign (tree_expression *exp, jit_value *rhs,
-                           bool artificial = false);
-
-    jit_value * do_assign (const std::string& lhs, jit_value *rhs, bool print,
-                           bool artificial = false);
-
-    jit_value * visit (tree *tee) { return visit (*tee); }
-
-    jit_value * visit (tree& tee);
-
-    typedef std::list<jit_block *> block_list;
-    block_list m_breaks;
-    block_list m_continues;
-
-    void finish_breaks (jit_block *dest, const block_list& lst);
-  };
-
-  // Convert from the low level Octave IR to LLVM
-  class
-  jit_convert_llvm : public jit_ir_walker
-  {
-  public:
-
-    llvm::Function * convert_loop (const jit_module& module,
-                                   const jit_block_list& blocks,
-                                   const std::list<jit_value *>& constants,
-                                   const std::string& llvm_function_name);
-
-    jit_function convert_function (const jit_module& module,
-                                   const jit_block_list& blocks,
-                                   const std::list<jit_value *>& constants,
-                                   octave_user_function& fcn,
-                                   const std::vector<jit_type *>& args);
-
-    // arguments to the llvm::Function for loops
-    const std::vector<std::pair<std::string, bool>>& get_arguments(void) const
-    { return m_argument_vec; }
-
-#define JIT_METH(clname)                        \
-    virtual void visit (jit_ ## clname&);
-
-    JIT_VISIT_IR_CLASSES;
-
-#undef JIT_METH
-
-  private:
-
-    // name -> argument index (used for compiling functions)
-    std::map<std::string, int> m_argument_index;
-
-    std::vector<std::pair<std::string, bool>> m_argument_vec;
-
-    // name -> llvm argument (used for compiling loops)
-    std::map<std::string, llvm::Value *> m_arguments;
-
-    bool m_converting_function;
-
-    // only used if we are converting a function
-    jit_function m_creating;
-
-    llvm::Function *m_function;
-    llvm::BasicBlock *m_prelude;
-
-    void convert (const jit_block_list& blocks,
-                  const std::list<jit_value *>& constants);
-
-    void finish_phi (jit_phi *phi);
-
-    void visit (jit_value *jvalue)
-    {
-      return visit (*jvalue);
-    }
-
-    void visit (jit_value& jvalue)
-    {
-      jvalue.accept (*this);
-    }
-  };
-
-  // type inference and SSA construction on the low level Octave IR
-  class
-  jit_infer
-  {
-  public:
-
-    typedef jit_convert::variable_map variable_map;
-
-    jit_infer (jit_factory& afactory, jit_block_list& ablocks,
-               const variable_map& avmap);
-
-    jit_block_list& get_blocks (void) const { return m_blocks; }
-
-    jit_factory& get_factory (void) const { return m_factory; }
-
-    void infer (void);
-
-  private:
-
-    jit_block_list& m_blocks;
-    jit_factory& m_factory;
-    const variable_map& m_vmap;
-    std::list<jit_instruction *> m_worklist;
-
-    void append_users (jit_value *v);
-
-    void append_users_term (jit_terminator *term);
-
-    void construct_ssa (void);
-
-    void do_construct_ssa (jit_block& block, std::size_t avisit_count);
-
-    jit_block& entry_block (void) { return *m_blocks.front (); }
-
-    jit_block& final_block (void) { return *m_blocks.back (); }
-
-    void place_releases (void);
-
-    void push_worklist (jit_instruction *instr);
-
-    void remove_dead ();
-
-    void release_dead_phi (jit_block& ablock);
-
-    void release_temp (jit_block& ablock, std::set<jit_value *>& temp);
-
-    void simplify_phi (void);
-
-    void simplify_phi (jit_phi& phi);
-  };
-
-
-  class jit_module;
-
-  class
-  tree_jit
-  {
-    // ----- Constructor/destructor (singleton pattern) -----
-
-  public:
-
-    ~tree_jit (void);
-
-  private:
-
-    tree_jit (void);
-    static tree_jit& instance (void);
-
-    // ----- Initialization -----
-
-  private:
-
-    static bool initialized;
-    bool do_initialize (void);
-
-    // ----- LLVM context -----
-
-  public:
-
-    static llvm::LLVMContext llvm_context;
-
-    // ----- Target machine ----
-
-  public:
-
-    static const llvm::TargetMachine* get_target_machine (void)
-    { return instance ().target_machine; }
-
-  private:
-
-    llvm::TargetMachine *target_machine;
-
-    // ----- Create LLVM modules and engines -----
-
-  public:
-
-    static jit::ModuleOwner
-    open_new_module (const std::string& module_name = generate_unique_module_name ());
-
-    static jit::EngineOwner
-    create_new_engine (jit::ModuleOwner module_owner);
-
-  private:
-
-    jit::ModuleOwner
-    do_open_new_module (const std::string& module_name) const;
-
-    // ----- Registering JIT modules (module+engine pairs) -----
-
-  public:
-
-    static void register_jit_module (jit_module* jm)
-    { instance ().do_register_jit_module (jm); }
-
-    static void unregister_jit_module (jit_module* jm)
-    { instance ().do_unregister_jit_module (jm); }
-
-  private:
-
-    // List of all currently registered jit modules
-    std::list<jit_module*> jm_list;
-    void do_register_jit_module (jit_module* jm);
-    void do_unregister_jit_module (jit_module* jm);
-    void do_dump_all_modules (void) const;
-
-    // ----- Symbol resolution -----
-
-  public:
-
-    static void* getPointerToNamedFunction (const std::string &name)
-    { return instance ().do_getPointerToNamedFunction (name); }
-
-    static uint64_t getSymbolAddress (const std::string &name)
-    { return instance ().do_getSymbolAddress (name); }
-
-  private:
-
-    void* do_getPointerToNamedFunction (const std::string &Name) const;
-
-    uint64_t do_getSymbolAddress (const std::string &name) const;
-
-    // ----- Generate unique identifiers -----
-
-  public:
-
-    static std::string generate_unique_forloop_name (void)
-    {
-      return std::string ("jittedForLoop")
-             + std::to_string (next_forloop_number ++);
-    }
-    // FIXME: Check that the identifier does not exist
-
-    static std::string generate_unique_function_name (void)
-    {
-      return std::string ("jittedFunction")
-             + std::to_string (next_function_number ++);
-    }
-    // FIXME: Check that the identifier does not exist
-
-    static std::string generate_unique_module_name (void)
-    {
-      return std::string ("octaveJITModule")
-             + std::to_string (next_module_number ++);
-    }
-    // FIXME: Check that the identifier does not exist
-
-  private:
-
-    static int next_forloop_number;
-    static int next_function_number;
-    static int next_module_number;
-
-    // ----- JIT and execute ASTs -----
-
-  public:
-
-    static bool execute (tree_simple_for_command& cmd,
-                         const octave_value& bounds)
-    { return instance ().do_execute (cmd, bounds); }
-
-    static bool execute (tree_while_command& cmd)
-    { return instance ().do_execute (cmd); }
-
-    static bool execute (octave_user_function& fcn,
-                         const octave_value_list& args,
-                         octave_value_list& retval)
-    { return instance ().do_execute (fcn, args, retval); }
-
-  private:
-
-    bool do_execute (tree_simple_for_command& cmd,
-                     const octave_value& bounds);
-
-    bool do_execute (tree_while_command& cmd);
-
-    bool do_execute (octave_user_function& fcn,
-                     const octave_value_list& args,
-                     octave_value_list& retval);
-
-    // ----- Miscellaneous -----
-
-    bool enabled (void);
-
-    std::size_t trip_count (const octave_value& bounds) const;
-  };
-
-
-  class
-  jit_module
-  {
-    // TODO: Encapsulate all operations that can modify the module,
-    //       and prevent them if the module has been finalized
-
-    // TODO: Consider creating the engine at the end only?
-    //       I have read somewhere that this is more efficient (nor sure)
-
-  public:
-
-    // Create an open module and associated JIT engine
-    jit_module (const std::string& module_name
-                = tree_jit::generate_unique_module_name ());
-
-    // Delete the underlying JIT engine
-    ~jit_module ();
-
-    // Create an LLVM function in the module, with external linkage
-    llvm::Function*
-    create_llvm_function (llvm::FunctionType *ftype,
-                          const llvm::Twine &name) const;
-
-    // Create a global in the module, with external linkage
-    llvm::GlobalVariable*
-    create_global_variable (llvm::Type *type, bool is_constant,
-                            const llvm::Twine& name) const;
-
-    // Create or insert an LLVM Function declaration for an intrinsic,
-    // and return it
-    llvm::Function*
-    get_intrinsic_declaration (std::size_t id,
-                               std::vector<llvm::Type*> types) const;
-
-    // Underlying type of enums defined in yet-inconplete types
-    typedef unsigned llvm_gv_linkage;  // FIXME: autoconf this
-
-    // add_global_mapping tells the execution engine where a specified
-    // global value (variable or function) is
-    template <typename ptr_type>
-    void add_global_mapping (const llvm::GlobalValue* gv, ptr_type p) const
-    {
-      do_add_global_mapping (gv, reinterpret_cast<void *> (p));
-    }
-
-    // Return the address of the specified function.
-    uint64_t getFunctionAddress (const std::string &name) const;
-
-    // Optimize a function in the LLVM module
-    void optimize (llvm::Function *fn) const;
-
-    // FIXME: Once this has been called, we should not be able
-    // to change anything in the module...
-    void finalizeObject (void);
-
-  private:
-
-    void do_add_global_mapping (const llvm::GlobalValue* gv, void* p) const;
-
-    llvm::Module *m_module;
-    llvm::ExecutionEngine *m_engine;
-  };
-
-
-  class
-  jit_info : public jit_module
-  {
-  public:
-
-    // we use a pointer here so we don't have to include ov.h
-    typedef std::map<std::string, const octave_value *> vmap;
-
-    jit_info (tree& tee);
-
-    jit_info (tree& tee, const octave_value& for_bounds);
-
-    jit_info (tree_simple_for_command& tee, const octave_value& for_bounds);
-
-    bool execute (const vmap& extra_vars = vmap ()) const;
-
-    bool match (const vmap& extra_vars = vmap ()) const;
-
-  private:
-
-    typedef jit_convert::type_bound type_bound;
-    typedef jit_convert::type_bound_vector type_bound_vector;
-    typedef void (*jited_function)(octave_base_value**);
-
-    void compile (tree& tee, jit_type *for_bounds = 0);
-
-    octave_value find (const vmap& extra_vars, const std::string& vname) const;
-
-    // LLVM function associated to this jit_info object
-    std::string m_llvm_function_name;
-    jited_function m_function;
-
-    std::vector<std::pair<std::string, bool>> m_arguments;
-    type_bound_vector m_bounds;
-  };
-
-
-  class
-  jit_function_info : public jit_module
-  {
-  public:
-
-    jit_function_info (octave_user_function& fcn,
-                       const octave_value_list& ov_args);
-
-    bool execute (const octave_value_list& ov_args,
-                  octave_value_list& retval) const;
-
-    bool match (const octave_value_list& ov_args) const;
-
-  private:
-
-    typedef octave_base_value *(*jited_function)(octave_base_value**);
-
-    // LLVM function associated to this jit_info object
-    std::string m_llvm_function_name;
-    jited_function m_function;
-
-    std::vector<jit_type *> m_argument_types;
-  };
-}
-
-#endif
-
-#endif
--- a/libinterp/parse-tree/pt-loop.cc	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/parse-tree/pt-loop.cc	Tue Aug 10 16:42:29 2021 -0400
@@ -42,9 +42,6 @@
     delete m_list;
     delete m_lead_comm;
     delete m_trail_comm;
-#if defined (HAVE_LLVM)
-    delete m_compiled;
-#endif
   }
 
   // For.
@@ -57,9 +54,6 @@
     delete m_list;
     delete m_lead_comm;
     delete m_trail_comm;
-#if defined (HAVE_LLVM)
-    delete m_compiled;
-#endif
   }
 
   tree_complex_for_command::~tree_complex_for_command (void)
--- a/libinterp/parse-tree/pt-loop.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/parse-tree/pt-loop.h	Tue Aug 10 16:42:29 2021 -0400
@@ -32,11 +32,9 @@
 
 #include "pt-cmd.h"
 #include "pt-walk.h"
-#include "pt-jit.h"
 
 namespace octave
 {
-  class jit_info;
   class tree_argument_list;
   class tree_expression;
   class tree_statement_list;
@@ -50,9 +48,6 @@
     tree_while_command (int l = -1, int c = -1)
       : tree_command (l, c), m_expr (nullptr), m_list (nullptr),
         m_lead_comm (nullptr), m_trail_comm (nullptr)
-#if defined (HAVE_LLVM)
-      , m_compiled (nullptr)
-#endif
     { }
 
     tree_while_command (tree_expression *e,
@@ -61,9 +56,6 @@
                         int l = -1, int c = -1)
       : tree_command (l, c), m_expr (e), m_list (nullptr),
         m_lead_comm (lc), m_trail_comm (tc)
-#if defined (HAVE_LLVM)
-      , m_compiled (nullptr)
-#endif
     { }
 
     tree_while_command (tree_expression *e, tree_statement_list *lst,
@@ -72,9 +64,6 @@
                         int l = -1, int c = -1)
       : tree_command (l, c), m_expr (e), m_list (lst), m_lead_comm (lc),
         m_trail_comm (tc)
-#if defined (HAVE_LLVM)
-      , m_compiled (nullptr)
-#endif
     { }
 
     // No copying!
@@ -98,13 +87,6 @@
       tw.visit_while_command (*this);
     }
 
-#if defined (HAVE_LLVM)
-    // some functions use by tree_jit
-    jit_info * get_info (void) const { return m_compiled; }
-
-    void stash_info (jit_info *jinfo) { m_compiled = jinfo; }
-#endif
-
   protected:
 
     // Expression to test.
@@ -118,13 +100,6 @@
 
     // Comment preceding ENDWHILE token.
     comment_list *m_trail_comm;
-
-  private:
-
-#if defined (HAVE_LLVM)
-    // compiled version of the loop
-    jit_info *m_compiled;
-#endif
   };
 
   // Do-Until.
@@ -175,9 +150,6 @@
       : tree_command (l, c), m_parallel (false), m_lhs (nullptr),
         m_expr (nullptr), m_maxproc (nullptr), m_list (nullptr),
         m_lead_comm (nullptr), m_trail_comm (nullptr)
-#if defined (HAVE_LLVM)
-      , m_compiled (nullptr)
-#endif
     { }
 
     tree_simple_for_command (bool parallel_arg, tree_expression *le,
@@ -190,9 +162,6 @@
       : tree_command (l, c), m_parallel (parallel_arg), m_lhs (le),
         m_expr (re), m_maxproc (maxproc_arg), m_list (lst),
         m_lead_comm (lc), m_trail_comm (tc)
-#if defined (HAVE_LLVM)
-      , m_compiled (0)
-#endif
     { }
 
     // No copying!
@@ -222,19 +191,6 @@
       tw.visit_simple_for_command (*this);
     }
 
-#if defined (HAVE_LLVM)
-    // some functions use by tree_jit
-    jit_info * get_info (void) const
-    {
-      return m_compiled;
-    }
-
-    void stash_info (jit_info *jinfo)
-    {
-      m_compiled = jinfo;
-    }
-#endif
-
   private:
     // TRUE means operate in parallel (subject to the value of the
     // maxproc expression).
@@ -258,11 +214,6 @@
 
     // Comment preceding ENDFOR token.
     comment_list *m_trail_comm;
-
-#if defined (HAVE_LLVM)
-    // compiled version of the loop
-    jit_info *m_compiled;
-#endif
   };
 
   class tree_complex_for_command : public tree_command
--- a/libinterp/template-inst/Array-jit.cc	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2012-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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 of the License, or
-// (at your option) any later version.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined (HAVE_LLVM)
-
-#include "Array.h"
-#include "Array.cc"
-
-#include "jit-ir.h"
-
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class Array<octave::idx_vector>;
-extern template class Array<octave_idx_type>;
-
-NO_INSTANTIATE_ARRAY_SORT_API (octave::jit_function, OCTINTERP_API);
-
-// Visibility attributes are ignored on template instantiation.
-// As a work-around, set visibility to default overriding compiler options.
-#pragma GCC visibility push(default)
-INSTANTIATE_ARRAY (octave::jit_function, OCTINTERP_API);
-#pragma GCC visibility pop
-
-#if defined (Cell_h)
-#  error Must not include Cell.h in Array-jit.h
-#  error This causes problems on MSVC
-#endif
-
-#endif
--- a/libinterp/template-inst/module.mk	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/template-inst/module.mk	Tue Aug 10 16:42:29 2021 -0400
@@ -1,3 +1,2 @@
 TEMPLATE_INST_SRC = \
-  %reldir%/Array-tc.cc \
-  %reldir%/Array-jit.cc
+  %reldir%/Array-tc.cc
--- a/libinterp/usage.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/libinterp/usage.h	Tue Aug 10 16:42:29 2021 -0400
@@ -34,12 +34,11 @@
 
 // Usage message
 static const char *usage_string =
-  "octave [-HVWdfhiqvx] [--debug] [--debug-jit] [--doc-cache-file file]\n\
-       [--echo-commands] [--eval CODE] [--exec-path path]\n\
-       [--experimental-terminal-widget] [--gui] [--help] [--image-path path]\n\
-       [--info-file file] [--info-program prog] [--interactive]\n\
-       [--jit-compiler] [--line-editing] [--no-gui] [--no-history]\n\
-       [--no-init-file] [--no-init-path] [--no-line-editing]\n\
+  "octave [-HVWdfhiqvx] [--debug] [--doc-cache-file file] [--echo-commands]\n\
+       [--eval CODE] [--exec-path path] [--experimental-terminal-widget]\n\
+       [--gui] [--help] [--image-path path] [--info-file file]\n\
+       [--info-program prog] [--interactive] [--line-editing] [--no-gui]\n\
+       [--no-history] [--no-init-file] [--no-init-path] [--no-line-editing]\n\
        [--no-site-file] [--no-window-system] [--norc] [-p path]\n\
        [--path path] [--persist] [--server] [--silent] [--traditional]\n\
        [--verbose] [--version] [file]";
@@ -58,7 +57,6 @@
 \n\
   --built-in-docstrings-file FILE Use docs for built-ins from FILE.\n\
   --debug, -d             Enter parser debugging mode.\n\
-  --debug-jit             Enable JIT compiler debugging/tracing.\n\
   --doc-cache-file FILE   Use doc cache file FILE.\n\
   --echo-commands, -x     Echo commands as they are executed.\n\
   --eval CODE             Evaluate CODE.  Exit when done unless --persist.\n\
@@ -71,7 +69,6 @@
   --info-file FILE        Use top-level info file FILE.\n\
   --info-program PROGRAM  Use PROGRAM for reading info files.\n\
   --interactive, -i       Force interactive behavior.\n\
-  --jit-compiler          Enable the JIT compiler.\n\
   --line-editing          Force readline use for command-line editing.\n\
   --no-gui                Disable the graphical user interface.\n\
   --no-history, -H        Don't save commands to the history list\n\
--- a/liboctave/array/Array.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/liboctave/array/Array.h	Tue Aug 10 16:42:29 2021 -0400
@@ -242,14 +242,6 @@
 
   static OCTARRAY_API typename Array<T>::ArrayRep *nil_rep (void);
 
-protected:
-
-  //! For jit support
-  Array (T *sdata, octave_idx_type slen, octave_idx_type *adims, void *arep)
-    : m_dimensions (adims),
-      m_rep (reinterpret_cast<typename Array<T>::ArrayRep *> (arep)),
-      m_slice_data (sdata), m_slice_len (slen) { }
-
 public:
 
   //! Empty ctor (0 by 0).
@@ -839,18 +831,6 @@
   //! with supposedly equal dimensions (e.g. structs in the interpreter).
   OCTARRAY_API bool optimize_dimensions (const dim_vector& dv);
 
-  //@{
-  //! WARNING: Only call these functions from jit
-
-  int jit_ref_count (void) { return m_rep->m_count.value (); }
-
-  T * jit_slice_data (void) const { return m_slice_data; }
-
-  octave_idx_type * jit_dimensions (void) const { return m_dimensions.to_jit (); }
-
-  void * jit_array_rep (void) const { return m_rep; }
-  //@}
-
 private:
   OCTARRAY_API static void instantiation_guard ();
 };
--- a/liboctave/array/MArray.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/liboctave/array/MArray.h	Tue Aug 10 16:42:29 2021 -0400
@@ -63,12 +63,6 @@
 OCTAVE_API
 MArray : public Array<T>
 {
-protected:
-
-  // For jit support
-  MArray (T *sdata, octave_idx_type slen, octave_idx_type *adims, void *arep)
-    : Array<T> (sdata, slen, adims, arep) { }
-
 public:
 
   MArray (void) : Array<T> () { }
--- a/liboctave/array/dNDArray.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/liboctave/array/dNDArray.h	Tue Aug 10 16:42:29 2021 -0400
@@ -64,11 +64,6 @@
 
   NDArray (const charNDArray&);
 
-  // For jit support only
-  NDArray (double *sdata, octave_idx_type slen, octave_idx_type *adims,
-           void *arep)
-    : MArray<double> (sdata, slen, adims, arep) { }
-
   NDArray& operator = (const NDArray& a)
   {
     MArray<double>::operator = (a);
--- a/liboctave/array/dim-vector.h	Mon Aug 09 16:30:48 2021 +0200
+++ b/liboctave/array/dim-vector.h	Tue Aug 10 16:42:29 2021 -0400
@@ -170,12 +170,6 @@
 
   OCTAVE_API void chop_all_singletons (void);
 
-  // WARNING: Only call by jit
-  octave_idx_type * to_jit (void) const
-  {
-    return m_dims;
-  }
-
 private:
 
   explicit dim_vector (octave_idx_type ndims)
@@ -200,9 +194,6 @@
     std::copy_n (dv.m_dims, m_num_dims, m_dims);
   }
 
-  // FIXME: Should be private, but required by array constructor for jit
-  explicit dim_vector (octave_idx_type *r) : m_dims (r) { }
-
   dim_vector (dim_vector&& dv)
     : m_num_dims (0), m_dims (nullptr)
   {
--- a/m4/acinclude.m4	Mon Aug 09 16:30:48 2021 +0200
+++ b/m4/acinclude.m4	Tue Aug 10 16:42:29 2021 -0400
@@ -2870,242 +2870,6 @@
   fi
 ])
 dnl
-dnl Check for CallInst::addAttribute API
-dnl
-AC_DEFUN([OCTAVE_LLVM_CALLINST_ADDATTRIBUTE_API], [
-  AC_CACHE_CHECK([if llvm::CallInst::addAttribute's arg type is llvm::Attributes],
-    [octave_cv_callinst_addattribute_arg_is_attributes],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-          #include <llvm/IR/Instructions.h>
-          #include <llvm/IR/Attributes.h>
-#else
-          #include <llvm/Instructions.h>
-          #include <llvm/Attributes.h>
-#endif
-          ]], [[
-          llvm::CallInst *callinst;
-          llvm::AttrBuilder attr_builder;
-          attr_builder.addAttribute(llvm::Attributes::StructRet);
-          llvm::Attributes attrs = llvm::Attributes::get(llvm::getGlobalContext(), attr_builder);
-          callinst->addAttribute (1, attrs);
-        ]])],
-        octave_cv_callinst_addattribute_arg_is_attributes=yes,
-        octave_cv_callinst_addattribute_arg_is_attributes=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_callinst_addattribute_arg_is_attributes = yes; then
-    AC_DEFINE(CALLINST_ADDATTRIBUTE_ARG_IS_ATTRIBUTES, 1,
-      [Define to 1 if llvm::CallInst:addAttribute arg type is llvm::Attributes.])
-  fi
-])
-dnl
-dnl Check for Function::addAttribute API
-dnl
-AC_DEFUN([OCTAVE_LLVM_FUNCTION_ADDATTRIBUTE_API], [
-  AC_CACHE_CHECK([if llvm::Function::addAttribute's arg type is llvm::Attributes],
-    [octave_cv_function_addattribute_arg_is_attributes],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-          #include <llvm/IR/Function.h>
-          #include <llvm/IR/Attributes.h>
-          #include <llvm/IR/LLVMContext.h>
-#else
-          #include <llvm/Function.h>
-          #include <llvm/Attributes.h>
-          #include <llvm/LLVMContext.h>
-#endif
-          ]], [[
-          llvm::Function *llvm_function;
-          llvm::AttrBuilder attr_builder;
-          attr_builder.addAttribute(llvm::Attributes::StructRet);
-          llvm::Attributes attrs = llvm::Attributes::get(llvm::getGlobalContext(), attr_builder);
-          llvm_function->addAttribute (1, attrs);
-        ]])],
-        octave_cv_function_addattribute_arg_is_attributes=yes,
-        octave_cv_function_addattribute_arg_is_attributes=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_function_addattribute_arg_is_attributes = yes; then
-    AC_DEFINE(FUNCTION_ADDATTRIBUTE_ARG_IS_ATTRIBUTES, 1,
-      [Define to 1 if llvm::Function:addAttribute arg type is llvm::Attributes.])
-  fi
-])
-dnl
-dnl Check for Function::addFnAttr API
-dnl
-AC_DEFUN([OCTAVE_LLVM_FUNCTION_ADDFNATTR_API], [
-  AC_CACHE_CHECK([if llvm::Function::addFnAttr's arg type is llvm::Attributes],
-    [octave_cv_function_addfnattr_arg_is_attributes],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-          #include <llvm/IR/Function.h>
-          #include <llvm/IR/Attributes.h>
-#else
-          #include <llvm/Function.h>
-          #include <llvm/Attributes.h>
-#endif
-          ]], [[
-          llvm::Function *llvm_function;
-          llvm_function->addFnAttr (llvm::Attributes::AlwaysInline);
-        ]])],
-        octave_cv_function_addfnattr_arg_is_attributes=yes,
-        octave_cv_function_addfnattr_arg_is_attributes=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_function_addfnattr_arg_is_attributes = yes; then
-    AC_DEFINE(FUNCTION_ADDFNATTR_ARG_IS_ATTRIBUTES, 1,
-      [Define to 1 if llvm::Function:addFnAttr arg type is llvm::Attributes.])
-  fi
-])
-dnl
-dnl Check for llvm::createAlwaysInlinerPass
-dnl
-AC_DEFUN([OCTAVE_LLVM_HAS_CREATEALWAYSINLINERPASS], [
-  AC_CACHE_CHECK([if llvm::createAlwaysInlinerPass exists],
-    [octave_cv_llvm_has_createalwaysinlinerpass],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-          #include <llvm/Transforms/IPO.h>
-          ]], [[
-          llvm::Pass *p;
-          p = llvm::createAlwaysInlinerPass ();
-        ]])],
-        octave_cv_llvm_has_createalwaysinlinerpass=yes,
-        octave_cv_llvm_has_createalwaysinlinerpass=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_llvm_has_createalwaysinlinerpass = yes; then
-    AC_DEFINE(LLVM_HAS_CREATEALWAYSINLINERPASS, 1,
-      [Define to 1 if llvm::createAlwaysInlinerPass exists.])
-  fi
-])
-dnl
-dnl Check llvm::IRBuilder API
-dnl
-AC_DEFUN([OCTAVE_LLVM_IRBUILDER_API], [
-  AC_CACHE_CHECK([if llvm::IRBuilder has two template arguments],
-    [octave_cv_llvm_irbuilder_has_two_template_args],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-          #include <llvm/IR/LLVMContext.h>
-#else
-          #include <llvm/LLVMContext.h>
-#endif
-#if defined (HAVE_LLVM_IR_IRBUILDER_H)
-          #include <llvm/IR/IRBuilder.h>
-#elif defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
-          #include <llvm/Support/IRBuilder.h>
-#else
-          #include <llvm/IRBuilder.h>
-#endif
-          using namespace llvm;
-          ]], [[
-          LLVMContext c;
-          IRBuilder<ConstantFolder,IRBuilderDefaultInserter>  irb (c);
-        ]])],
-        octave_cv_llvm_irbuilder_has_two_template_args=yes,
-        octave_cv_llvm_irbuilder_has_two_template_args=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_llvm_irbuilder_has_two_template_args = yes; then
-    AC_DEFINE(LLVM_IRBUILDER_HAS_TWO_TEMPLATE_ARGS, 1,
-      [Define to 1 if llvm::IRBuilder has two template arguments.])
-  fi
-])
-dnl
-dnl Check llvm::IRBuilder::CreateConstInBoundsGEP1_32 API
-dbl
-AC_DEFUN([OCTAVE_LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_API], [
-  AC_CACHE_CHECK([if llvm::IRBuilder::CreateConstInBoundsGEP1_32 requires a type argument],
-    [octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_IRBUILDER_H)
-          #include <llvm/IR/IRBuilder.h>
-#elif defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
-          #include <llvm/Support/IRBuilder.h>
-#else
-          #include <llvm/IRBuilder.h>
-#endif
-          ]], [[
-          llvm::LLVMContext c;
-          llvm::IRBuilder<>  irb (c);
-          llvm::Value *v;
-          v = irb.CreateConstInBoundsGEP1_32 ((llvm::Value *) nullptr, 0);
-        ]])],
-        octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type=no,
-        octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type=yes)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type = yes; then
-    AC_DEFINE(LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_REQUIRES_TYPE, 1,
-      [Define to 1 if llvm::IRBuilder::CreateConstInBoundsGEP1_32 requires a type argument.])
-  fi
-])
-dnl
-dnl Check for legacy::PassManager API
-dnl
-AC_DEFUN([OCTAVE_LLVM_LEGACY_PASSMANAGER_API], [
-  AC_CACHE_CHECK([if llvm::legacy::PassManager exists],
-    [octave_cv_legacy_passmanager],
-    [AC_LANG_PUSH(C++)
-      save_LIBS="$LIBS"
-      LIBS="$LLVM_LIBS $LIBS"
-      AC_LINK_IFELSE(
-        [AC_LANG_PROGRAM([[
-          #include <llvm/IR/LegacyPassManager.h>
-          ]], [[
-          llvm::Module *module;
-          llvm::legacy::PassManager *module_pass_manager;
-          llvm::legacy::FunctionPassManager *pass_manager;
-          module_pass_manager = new llvm::legacy::PassManager ();
-          pass_manager = new llvm::legacy::FunctionPassManager (module);
-        ]])],
-        octave_cv_legacy_passmanager=yes,
-        octave_cv_legacy_passmanager=no)
-      LIBS="$save_LIBS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_legacy_passmanager = yes; then
-    AC_DEFINE(LEGACY_PASSMANAGER, 1,
-      [Define to 1 if LLVM::legacy::PassManager exists.])
-  fi
-])
-dnl
-dnl Check for raw_fd_ostream API
-dnl
-AC_DEFUN([OCTAVE_LLVM_RAW_FD_OSTREAM_API], [
-  AC_CACHE_CHECK([if llvm::raw_fd_ostream's arg type is llvm::sys:fs],
-    [octave_cv_raw_fd_ostream_arg_is_llvm_sys_fs],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-          #include <llvm/Support/raw_os_ostream.h>
-          ]], [[
-          std::string str;
-          llvm::raw_fd_ostream fout ("", str, llvm::sys::fs::F_Binary);
-        ]])],
-        octave_cv_raw_fd_ostream_arg_is_llvm_sys_fs=yes,
-        octave_cv_raw_fd_ostream_arg_is_llvm_sys_fs=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_raw_fd_ostream_arg_is_llvm_sys_fs = yes; then
-    AC_DEFINE(RAW_FD_OSTREAM_ARG_IS_LLVM_SYS_FS, 1,
-      [Define to 1 if LLVM::raw_fd_ostream arg type is llvm::sys:fs.])
-  fi
-])
-dnl
 dnl Check if MIPS processor is target and quiet signalling NaN value is
 dnl opposite of IEEE 754-2008 standard used by all other architectures.
 dnl
--- a/test/jit.tst	Mon Aug 09 16:30:48 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,601 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2012-2021 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## This file is part of Octave.
-##
-## Octave 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 of the License, or
-## (at your option) any later version.
-##
-## Octave 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 Octave; see the file COPYING.  If not, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## Note: unit tests involving try/catch blocks are currently disabled since
-##   the JIT in its current form is not compatible with exception handling.
-
-## Turn on JIT and set defaults before running tests
-%!testif HAVE_LLVM
-%! global __old_jit_enable__;
-%! global __old_jit_startcnt__;
-%! __old_jit_enable__ = jit_enable (true);
-%! __old_jit_startcnt__ = jit_startcnt (1000);
-
-## Test some simple cases that compile.
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! for i=1:1e6
-%!   if (i < 5)
-%!     break;
-%!   else
-%!     break;
-%!   endif
-%! endfor
-%! assert (i, 1);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! while (1)
-%!   if (1)
-%!     break;
-%!   else
-%!     break;
-%!   endif
-%! endwhile
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! do
-%!   break;
-%! until (0)
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! do
-%!   if (1)
-%!     break;
-%!   end;
-%! until (0)
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! i=1;
-%! do
-%!   continue;
-%!   i=i+1;
-%! until (1)
-%! assert (i, 1);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! for i=1:1e6
-%!   if (i == 100)
-%!     break;
-%!   endif
-%! endfor
-%! assert (i, 100);
-%! assert (jit_failcnt, 0);
-
-## Also test parfor keyword
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! parfor i=1:1e6
-%!   if (i == 100)
-%!     break;
-%!   endif
-%! endparfor
-%! assert (i, 100);
-%! assert (jit_failcnt, 0);
-
-## Test some switch statements
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! do
-%!   switch (1)
-%!   end;
-%! until(1)
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! do
-%!   switch (1)
-%!   case 1
-%!     break;
-%!   end;
-%! until(1)
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! do
-%!   switch (1)
-%!   otherwise
-%!     break;
-%!   end;
-%! until(1)
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! do
-%!   switch (1)
-%!   case 1
-%!     break;
-%!   otherwise
-%!     break;
-%!   end;
-%! until(1)
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! i=0;
-%! a=0;
-%! b=0;
-%! do
-%!   i=i+1;
-%!   switch (i)
-%!   case 1
-%!     continue;
-%!   case 2
-%!     b=1;
-%!     continue;
-%!   case 4
-%!     break;
-%!   otherwise
-%!     a=a+5;
-%!   end;
-%!   a=a+1;
-%! until(0);
-%! assert (i, 4);
-%! assert (a, 6);
-%! assert (b, 1);
-%! assert (jit_failcnt, 0);
-
-## Some more complex calculations
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! inc = 1e-5;
-%! result = 0;
-%! for ii = 0:inc:1
-%!   result = result + inc * (1/3 * ii * ii);
-%! endfor
-%! assert (abs (result - 1/9) < 1e-5);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! inc = 1e-5;
-%! result = 0;
-%! for ii = 0:inc:1
-%!   ## the ^ operator's result is complex
-%!   result = result + inc * (1/3 * ii ^ 2);
-%! endfor
-%! assert (abs (result - 1/9) < 1e-5);
-%! assert (jit_failcnt, 0);
-
-## %!testif HAVE_LLVM
-## %! jit_failcnt (0);
-## %! temp = 1+1i;
-## %! nan = NaN;
-## %! while (1)
-## %!   temp = temp - 1i;
-## %!   temp = temp * nan;
-## %!   break;
-## %! endwhile
-## %! assert (imag (temp), 0);
-## %! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! temp = 1+1i;
-%! nan = NaN+1i;
-%! while (1)
-%!   nan = nan - 1i;
-%!   temp = temp - 1i;
-%!   temp = temp * nan;
-%!   break;
-%! endwhile
-%! assert (imag (temp), 0);
-%! assert (jit_failcnt, 0);
-
-## %!testif HAVE_LLVM
-## %! jit_failcnt (0);
-## %! temp = 1+1i;
-## %! while (1)
-## %!   temp = temp * 5;
-## %!   break;
-## %! endwhile
-## %! assert (temp, 5+5i);
-## %! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! nr = 1001;
-%! mat = zeros (1, nr);
-%! for i = 1:nr
-%!   mat(i) = i;
-%! endfor
-%! assert (mat == 1:nr);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! nr = 1001;
-%! mat = 1:nr;
-%! mat(end) = 0; # force mat to a matrix
-%! total = 0;
-%! for i = 1:nr
-%!   total = mat(i) + total;
-%! endfor
-%! assert (sum (mat) == total);
-%! assert (jit_failcnt, 0);
-
-## %!testif HAVE_LLVM
-## %! jit_failcnt (0);
-## %! nr = 1001;
-## %! mat = [3 1 5];
-## %! try
-## %!   for i = 1:nr
-## %!     if (i > 500)
-## %!       result = mat(100);
-## %!     else
-## %!       result = i;
-## %!     endif
-## %!   endfor
-## %! catch
-## %! end_try_catch
-## %! assert (result == 500);
-## %! assert (jit_failcnt, 0);
-
-%!function result = gen_test (n)
-%!  result = double (rand (1, n) > .01);
-%!endfunction
-
-%!function z = vectorized (A, K)
-%!  temp = ones (1, K);
-%!  z = conv (A, temp);
-%!  z = z > K-1;
-%!  z = conv (z, temp);
-%!  z = z(K:end-K+1);
-%!  z = z >= 1;
-%!endfunction
-
-%!function z = loopy (A, K)
-%!  z = A;
-%!  n = numel (A);
-%!  counter = 0;
-%!  for ii=1:n
-%!    if (z(ii))
-%!      counter = counter + 1;
-%!    else
-%!      if (counter > 0 && counter < K)
-%!        z(ii-counter:ii-1) = 0;
-%!      endif
-%!      counter = 0;
-%!    endif
-%!  endfor
-%!
-%!  if (counter > 0 && counter < K)
-%!    z(end-counter+1:end) = 0;
-%!  endif
-%!endfunction
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! test_set = gen_test (10000);
-%! assert (all (vectorized (test_set, 3) == loopy (test_set, 3)));
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! niter = 1001;
-%! i = 0;
-%! while (i < niter)
-%!   i = i + 1;
-%! endwhile
-%! assert (i == niter);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! niter = 1001;
-%! result = 0;
-%! m = [5 10];
-%! for i=1:niter
-%!   result = result + m(end);
-%! endfor
-%! assert (result == m(end) * niter);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! ndim = 100;
-%! result = 0;
-%! m = zeros (ndim);
-%! m(:) = 1:ndim^2;
-%! i = 1;
-%! while (i <= ndim)
-%!   for j = 1:ndim
-%!     result = result + m(i, j);
-%!    endfor
-%!   i = i + 1;
-%! endwhile
-%! assert (result == sum (sum (m)));
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! ndim = 100;
-%! m = zeros (ndim);
-%! i = 1;
-%! while (i <= ndim)
-%!   for j = 1:ndim
-%!     m(i, j) = (j - 1) * ndim + i;
-%!   endfor
-%!   i = i + 1;
-%! endwhile
-%! m2 = zeros (ndim);
-%! m2(:) = 1:(ndim^2);
-%! assert (all (m == m2));
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! ndim = 2;
-%! m = zeros (ndim, ndim, ndim, ndim);
-%! result = 0;
-%! i0 = 1;
-%! while (i0 <= ndim)
-%!   for i1 = 1:ndim
-%!     for i2 = 1:ndim
-%!       for i3 = 1:ndim
-%!         m(i0, i1, i2, i3) = 1;
-%!         m(i0, i1, i2, i3, 1, 1, 1, 1, 1, 1) = 1;
-%!         result = result + m(i0, i1, i2, i3);
-%!       endfor
-%!     endfor
-%!   endfor
-%!   i0 = i0 + 1;
-%! endwhile
-%! expected = ones (ndim, ndim, ndim, ndim);
-%! assert (all (m == expected));
-%! assert (result == sum (expected (:)));
-%! assert (jit_failcnt, 0);
-
-%!function test_divide ()
-%! for i=1:1e5
-%!   a = 1;
-%!   a / 0;
-%! endfor
-%!endfunction
-
-## %!testif HAVE_LLVM
-## %! jit_failcnt (0);
-## %! lasterr ("");
-## %! try
-## %!   test_divide ();
-## %! end_try_catch
-## %! assert (strcmp (lasterr (), "division by zero"));
-## %! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! while (1)
-%!   a = 0;
-%!   result = a / 1;
-%!   break;
-%! endwhile
-%! assert (result, 0);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! m = zeros (2, 1001);
-%! for i=1:1001
-%!   m(end, i) = i;
-%!   m(end - 1, end - i + 1) = i;
-%! endfor
-%! m2 = zeros (2, 1001);
-%! m2(1, :) = fliplr (1:1001);
-%! m2(2, :) = 1:1001;
-%! assert (m, m2);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! m = [1 2 3];
-%! for i=1:1001
-%!   m = sin (m);
-%!   break;
-%! endfor
-%! assert (m == sin ([1 2 3]));
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! i = 0;
-%! while i < 10
-%!   i += 1;
-%! endwhile
-%! assert (i == 10);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! i = 0;
-%! while i < 10
-%!   a = ++i;
-%! endwhile
-%! assert (i == 10);
-%! assert (a == 10);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! i = 0;
-%! while i < 10
-%!   a = i++;
-%! endwhile
-%! assert (i == 10);
-%! assert (a == 9);
-%! assert (jit_failcnt, 0);
-
-## %!testif HAVE_LLVM
-## %! jit_failcnt (0);
-## %! num = 2;
-## %! a = zeros (1, num);
-## %! i = 1;
-## %! while i <= num
-## %!   a(i) = norm (eye (i));
-## %!   ++i;
-## %! endwhile
-## %! assert (a, ones (1, num));
-## %! assert (jit_failcnt, 0);
-
-%!function test_compute_idom ()
-%! while (li <= length (l1) && si <= length (s1))
-%!   if (l1 (li) < s1 (si))
-%!     if (li == si)
-%!       break;
-%!     endif;
-%!     li++;
-%!   else
-%!     si++;
-%!   endif;
-%! endwhile
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! lasterr ("");
-%! try
-%!   test_compute_idom ();
-%! end_try_catch
-%! assert (! isempty (lasterr ()));
-%! assert (jit_failcnt, 1);
-
-%!function x = test_overload (a)
-%!  while (1)
-%!    x = a;
-%!    break;
-%!  endwhile
-%!endfunction
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! assert (test_overload (1), 1);
-%! assert (test_overload ([1 2]), [1 2]);
-%! assert (jit_failcnt, 0);
-
-%!function a = bubble (a = [3 2 1])
-%!  swapped = 1;
-%!  n = length (a);
-%!  while (swapped)
-%!    swapped = 0;
-%!    for i = 1:n-1
-%!      if (a(i) > a(i + 1))
-%!        swapped = 1;
-%!        temp = a(i);
-%!        a(i) = a(i + 1);
-%!        a(i + 1) = temp;
-%!      endif
-%!    endfor
-%!  endwhile
-%!endfunction
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! assert (bubble (), [1 2 3]);
-%! assert (jit_failcnt, 0);
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! a = 0;
-%! b = 1;
-%! for i=1:1e3
-%!   for j=1:2
-%!     a = a + b;
-%!   endfor
-%! endfor
-%! assert (a, 2000);
-%! assert (b, 1);
-%! assert (jit_failcnt, 0);
-
-%!test <53615>
-%! ## FIXME: No support for functions with complex input prototypes
-%! if (! __have_feature__ ("ENABLE_JIT"))
-%!   return;
-%! endif
-%! jit_failcnt (0);
-%! a = [1+1i 1+2i];
-%! b = 0;
-%! while (1)
-%!   b = a(1);
-%!   break;
-%! endwhile
-%! assert (b, a(1));
-%! assert (jit_failcnt, 0);
-
-%!function test_undef ()
-%!  for i=1:1e7
-%!    XXX;
-%!  endfor
-%!endfunction
-
-%!testif HAVE_LLVM
-%! jit_failcnt (0);
-%! lasterr ("");
-%! try
-%!   test_undef ();
-%! end_try_catch
-%! assert (strncmp (lasterr (), "'XXX' undefined near", 20));
-%! assert (jit_failcnt, 1);
-
-%!shared id
-%! id = @(x) x;
-
-%!test <53615>
-%! ## FIXME: No support for functions with complex input prototypes
-%! if (! __have_feature__ ("ENABLE_JIT"))
-%!   return;
-%! endif
-%! jit_failcnt (0);
-%! assert (id (1), 1);
-%! assert (id (1+1i), 1+1i);
-%! assert (id (1, 2), 1);
-%! assert (jit_failcnt, 0);
-
-## %!testif HAVE_LLVM
-## %! jit_failcnt (0);
-## %! lasterr ("");
-## %! try
-## %!   id ();
-## %! end_try_catch
-## %! assert (strncmp (lasterr (), "'x' undefined near", 18));
-## %! assert (jit_failcnt, 0);
-
-## Restore JIT settings
-%!testif HAVE_LLVM
-%! global __old_jit_enable__;
-%! global __old_jit_startcnt__;
-%! jit_enable (__old_jit_enable__);
-%! jit_startcnt (__old_jit_startcnt__);
-%! clear -g __old_jit_enable__ __old_jit_startcnt__;
--- a/test/module.mk	Mon Aug 09 16:30:48 2021 +0200
+++ b/test/module.mk	Tue Aug 10 16:42:29 2021 -0400
@@ -36,7 +36,6 @@
   %reldir%/inline-fcn.tst \
   %reldir%/integer.tst \
   %reldir%/io.tst \
-  %reldir%/jit.tst \
   %reldir%/leftdiv.tst \
   %reldir%/line-continue.tst \
   %reldir%/logical-index.tst \
@@ -128,11 +127,6 @@
 check-local: $(GENERATED_TEST_FILES) $(MEX_TEST_FUNCTIONS) | $(OCTAVE_INTERPRETER_TARGETS) %reldir%/$(octave_dirstamp)
 	$(AM_V_at)$(call run-octave-tests)
 
-if AMCOND_HAVE_LLVM
-check-jit: $(GENERATED_TEST_FILES) | $(OCTAVE_INTERPRETER_TARGETS) %reldir%/$(octave_dirstamp)
-	$(AM_V_at)$(call run-octave-tests,--jit-compiler)
-endif
-
 COVERAGE_DIR = %reldir%/coverage
 COVERAGE_INFO = $(COVERAGE_DIR)/$(PACKAGE).info