diff --git a/build-aux/common.mk b/build-aux/common.mk
--- a/build-aux/common.mk
+++ b/build-aux/common.mk
@@ -112,7 +112,7 @@
 XTRA_CFLAGS = @XTRA_CFLAGS@
 WARN_CFLAGS = @WARN_CFLAGS@
 AM_CFLAGS = $(XTRA_CFLAGS)
-ALL_CPPFLAGS = $(CPPFLAGS) $(HDF5_CPPFLAGS) $(Z_CPPFLAGS) $(LLVM_CPPFLAGS)
+ALL_CPPFLAGS = $(CPPFLAGS) $(HDF5_CPPFLAGS) $(Z_CPPFLAGS) $(LIBGCCJIT_CPPFLAGS) $(LLVM_CPPFLAGS)
 
 BUILD_CC = @BUILD_CC@
 BUILD_CFLAGS = @BUILD_CFLAGS@
@@ -254,6 +254,10 @@
 
 LAPACK_LIBS = @LAPACK_LIBS@
 
+LIBGCCJIT_CPPFLAGS = @LIBGCCJIT_CPPFLAGS@
+LIBGCCJIT_LDFLAGS = @LIBGCCJIT_LDFLAGS@
+LIBGCCJIT_LIBS = @LIBGCCJIT_LIBS@
+
 LLVM_CPPFLAGS = @LLVM_CPPFLAGS@
 LLVM_LDFLAGS = @LLVM_LDFLAGS@
 LLVM_LIBS = @LLVM_LIBS@
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -889,6 +889,24 @@
 AC_SUBST(LLVM_LIBS)
 AM_CONDITIONAL([AMCOND_HAVE_LLVM], [test -z "$warn_llvm"])
 
+AC_DEFINE(HAVE_JIT, 1, [Define to 1 if using a JIT (either LLVM or libgccjit).])
+
+# FIXME: add a test for this:
+AC_DEFINE(HAVE_GCCJIT, 1, [Define to 1 if libgccjit is available).])
+
+# FIXME: add CXXFLAGS etc
+# FIXME: hacking it in for now:
+LIBGCCJIT_CPPFLAGS=-I/home/david/coding/gcc-python/gcc-git-jit-blocks/src/gcc/jit/
+LIBGCCJIT_CXXFLAGS=-I/home/david/coding/gcc-python/gcc-git-jit-blocks/src/gcc/jit/
+LIBGCCJIT_LDFLAGS=-L/home/david/coding/gcc-python/gcc-git-jit-blocks/build/gcc
+LIBGCCJIT_LIBS=-lgccjit
+
+AC_SUBST(LIBGCCJIT_CPPFLAGS)
+AC_SUBST(LIBGCCJIT_CXXFLAGS)
+AC_SUBST(LIBGCCJIT_LDFLAGS)
+AC_SUBST(LIBGCCJIT_LIBS)
+
+
 ### Check for HDF5 library.
 
 save_CPPFLAGS="$CPPFLAGS"
@@ -2952,6 +2970,10 @@
   Java CPPFLAGS:               $JAVA_CPPFLAGS
   Java libraries:              $JAVA_LIBS
   LAPACK libraries:            $LAPACK_LIBS
+  libgccjit CPPFLAGS:          $LIBGCCJIT_CPPFLAGS
+  libgccjit CXXFLAGS:          $LIBGCCJIT_CXXFLAGS
+  libgccjit LDFLAGS:           $LIBGCCJIT_LDFLAGS
+  libgccjit libraries:         $LIBGCCJIT_LIBS
   LLVM CPPFLAGS:               $LLVM_CPPFLAGS
   LLVM LDFLAGS:                $LLVM_LDFLAGS
   LLVM libraries:              $LLVM_LIBS
diff --git a/libinterp/Makefile.am b/libinterp/Makefile.am
--- a/libinterp/Makefile.am
+++ b/libinterp/Makefile.am
@@ -32,6 +32,7 @@
   -I$(srcdir)/operators \
   -Iparse-tree -I$(srcdir)/parse-tree \
   -Icorefcn -I$(srcdir)/corefcn \
+  $(LIBGCCJIT_CPPFLAGS) \
   -I$(top_builddir)/libgnu -I$(top_srcdir)/libgnu
 
 AM_CFLAGS += $(WARN_CFLAGS)
diff --git a/libinterp/corefcn/jit-ir.cc b/libinterp/corefcn/jit-ir.cc
--- a/libinterp/corefcn/jit-ir.cc
+++ b/libinterp/corefcn/jit-ir.cc
@@ -30,10 +30,11 @@
 #include <config.h>
 #endif
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 
 #include "jit-ir.h"
 
+#if HAVE_LLVM
 #ifdef HAVE_LLVM_IR_FUNCTION_H
 #include <llvm/IR/BasicBlock.h>
 #include <llvm/IR/Instructions.h>
@@ -41,6 +42,7 @@
 #include <llvm/BasicBlock.h>
 #include <llvm/Instructions.h>
 #endif
+#endif
 
 #include "error.h"
 
@@ -208,11 +210,13 @@
   resize_arguments (0);
 }
 
+#if HAVE_LLVM
 llvm::BasicBlock *
 jit_instruction::parent_llvm (void) const
 {
   return mparent->to_llvm ();
 }
+#endif
 
 std::ostream&
 jit_instruction::short_print (std::ostream& os) const
@@ -388,11 +392,13 @@
   return term ? term->successor_count () : 0;
 }
 
+#if HAVE_LLVM
 llvm::BasicBlock *
 jit_block::to_llvm (void) const
 {
   return llvm::cast<llvm::BasicBlock> (llvm_value);
 }
+#endif
 
 std::ostream&
 jit_block::print_dom (std::ostream& os) const
@@ -661,11 +667,13 @@
   return false;
 }
 
+#if HAVE_LLVM
 llvm::PHINode *
 jit_phi::to_llvm (void) const
 {
   return llvm::cast<llvm::PHINode> (jit_value::to_llvm ());
 }
+#endif
 
 // -------------------- jit_terminator --------------------
 size_t
@@ -697,11 +705,13 @@
   return changed;
 }
 
+#if HAVE_LLVM
 llvm::TerminatorInst *
 jit_terminator::to_llvm (void) const
 {
   return llvm::cast<llvm::TerminatorInst> (jit_value::to_llvm ());
 }
+#endif
 
 // -------------------- jit_call --------------------
 bool
@@ -842,4 +852,4 @@
   return jit_typeinfo::end (ctx.value, ctx.index, ctx.count);
 }
 
-#endif
+#endif /* ifdef HAVE_JIT */
diff --git a/libinterp/corefcn/jit-ir.h b/libinterp/corefcn/jit-ir.h
--- a/libinterp/corefcn/jit-ir.h
+++ b/libinterp/corefcn/jit-ir.h
@@ -25,12 +25,16 @@
 #if !defined (octave_jit_ir_h)
 #define octave_jit_ir_h 1
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 
 #include <list>
 #include <stack>
 #include <set>
 
+#ifdef HAVE_GCCJIT
+#include "libgccjit++.h"
+#endif
+
 #include "jit-typeinfo.h"
 
 // The low level octave jit ir
@@ -188,7 +192,9 @@
 jit_value : public jit_internal_list<jit_value, jit_use>
 {
 public:
-  jit_value (void) : llvm_value (0), ty (0), mlast_use (0),
+  jit_value (void) : llvm_value (0),
+                     m_gcc_lvalue (), m_gcc_rvalue (),
+                     ty (0), mlast_use (0),
                      min_worklist (false) {}
 
   virtual ~jit_value (void);
@@ -212,10 +218,19 @@
 
   jit_type *type (void) const { return ty; }
 
+#if HAVE_LLVM
   llvm::Type *type_llvm (void) const
   {
     return ty ? ty->to_llvm () : 0;
   }
+#endif
+
+#if HAVE_GCCJIT
+  gccjit::type type_gccjit (void) const
+  {
+    return ty ? ty->to_gccjit () : gccjit::type ();
+  }
+#endif
 
   const std::string& type_name (void) const
   {
@@ -247,6 +262,7 @@
 
   virtual void accept (jit_ir_walker& walker) = 0;
 
+#if HAVE_LLVM
   bool has_llvm (void) const
   {
     return llvm_value;
@@ -262,6 +278,34 @@
   {
     llvm_value = compiled;
   }
+#endif
+
+#if 1
+  bool has_lvalue (void) const
+  {
+    return m_gcc_lvalue.get_inner_lvalue ();
+  }
+  bool has_rvalue (void) const
+  {
+    return m_gcc_rvalue.get_inner_rvalue ();
+  }
+  gccjit::lvalue as_lvalue (void) const
+  {
+    return m_gcc_lvalue;
+  }
+  gccjit::rvalue as_rvalue (void) const
+  {
+    return m_gcc_rvalue;
+  }
+  void stash_lvalue (gccjit::lvalue lvalue)
+  {
+    m_gcc_lvalue = lvalue;
+  }
+  void stash_rvalue (gccjit::rvalue rvalue)
+  {
+    m_gcc_rvalue = rvalue;
+  }
+#endif
 
 protected:
   std::ostream& print_indent (std::ostream& os, size_t indent = 0) const
@@ -271,7 +315,13 @@
     return os;
   }
 
+#if HAVE_LLVM
   llvm::Value *llvm_value;
+#endif
+#if HAVE_GCCJIT
+  gccjit::lvalue m_gcc_lvalue;
+  gccjit::rvalue m_gcc_rvalue;
+#endif
 private:
   jit_type *ty;
   jit_instruction *mlast_use;
@@ -371,22 +421,26 @@
     return marguments[i].value ();
   }
 
+#if HAVE_LLVM
   llvm::Value *argument_llvm (size_t i) const
   {
     assert (argument (i));
     return argument (i)->to_llvm ();
   }
+#endif
 
   jit_type *argument_type (size_t i) const
   {
     return argument (i)->type ();
   }
 
+#if HAVE_LLVM
   llvm::Type *argument_type_llvm (size_t i) const
   {
     assert (argument (i));
     return argument_type (i)->to_llvm ();
   }
+#endif
 
   std::ostream& print_argument (std::ostream& os, size_t i) const
   {
@@ -452,7 +506,9 @@
     return mlocation;
   }
 
+#if HAVE_LLVM
   llvm::BasicBlock *parent_llvm (void) const;
+#endif
 
   void stash_parent (jit_block *aparent,
                      std::list<jit_instruction *>::iterator alocation)
@@ -494,10 +550,10 @@
 jit_argument : public jit_value
 {
 public:
-  jit_argument (jit_type *atype, llvm::Value *avalue)
+  jit_argument (jit_type *atype/*, llvm::Value *avalue*/)
   {
     stash_type (atype);
-    stash_llvm (avalue);
+    //stash_llvm (avalue);
   }
 
   virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
@@ -584,6 +640,13 @@
 
   const std::string& name (void) const { return mname; }
 
+  std::string name_and_id (void) const
+  {
+    std::ostringstream os;
+    short_print (os);
+    return os.str ();
+  }
+
   jit_instruction *prepend (jit_instruction *instr);
 
   jit_instruction *prepend_after_phi (jit_instruction *instr);
@@ -719,7 +782,9 @@
     return os;
   }
 
+#if HAVE_LLVM
   llvm::BasicBlock *to_llvm (void) const;
+#endif
 
   std::list<jit_block *>::iterator location (void) const
   { return mlocation; }
@@ -975,10 +1040,12 @@
     return mincomming[i].value ();
   }
 
+#if HAVE_LLVM
   llvm::BasicBlock *incomming_llvm (size_t i) const
   {
     return incomming (i)->to_llvm ();
   }
+#endif
 
   virtual void construct_ssa (void) { }
 
@@ -1009,7 +1076,9 @@
     return os;
   }
 
+#if HAVE_LLVM
   llvm::PHINode *to_llvm (void) const;
+#endif
 
   JIT_VALUE_ACCEPT;
 private:
@@ -1037,10 +1106,12 @@
     return static_cast<jit_block *> (argument (idx));
   }
 
+#if HAVE_LLVM
   llvm::BasicBlock *successor_llvm (size_t idx = 0) const
   {
     return successor (idx)->to_llvm ();
   }
+#endif
 
   size_t successor_index (const jit_block *asuccessor) const;
 
@@ -1068,7 +1139,9 @@
 
   virtual bool infer (void);
 
+#if HAVE_LLVM
   llvm::TerminatorInst *to_llvm (void) const;
+#endif
 protected:
   virtual bool check_alive (size_t) const { return true; }
 private:
@@ -1106,10 +1179,12 @@
     return cond ()->short_print (os);
   }
 
+#if HAVE_LLVM
   llvm::Value *cond_llvm (void) const
   {
     return cond ()->to_llvm ();
   }
+#endif
 
   virtual size_t successor_count (void) const { return 2; }
 
@@ -1351,10 +1426,12 @@
     return result ()->type ();
   }
 
+#if HAVE_LLVM
   llvm::Value *result_llvm (void) const
   {
     return result ()->to_llvm ();
   }
+#endif
 
   virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
   {
@@ -1431,5 +1508,5 @@
 
 #undef JIT_VALUE_ACCEPT
 
+#endif /* ifdef HAVE_JIT */
 #endif
-#endif
diff --git a/libinterp/corefcn/jit-typeinfo.cc b/libinterp/corefcn/jit-typeinfo.cc
--- a/libinterp/corefcn/jit-typeinfo.cc
+++ b/libinterp/corefcn/jit-typeinfo.cc
@@ -531,9 +531,22 @@
 }
 
 // -------------------- jit_type --------------------
-jit_type::jit_type (const std::string& aname, jit_type *aparent,
-                    llvm::Type *allvm_type, bool askip_paren, int aid) :
-  mname (aname), mparent (aparent), llvm_type (allvm_type), mid (aid),
+jit_type::jit_type (const std::string& aname, jit_type *aparent
+#ifdef HAVE_LLVM                    
+                    , llvm::Type *allvm_type
+#endif
+#ifdef HAVE_LLVM                    
+                    , gccjit::type agcc_type
+#endif
+                    , bool askip_paren, int aid) :
+  mname (aname), mparent (aparent)
+#ifdef HAVE_LLVM                    
+  , llvm_type (allvm_type)
+#endif
+#ifdef HAVE_LLVM                    
+  , gccjit_type (agcc_type)
+#endif
+  , mid (aid),
   mdepth (aparent ? aparent->mdepth + 1 : 0), mskip_paren (askip_paren)
 {
   std::memset (msret, 0, sizeof (msret));
@@ -552,14 +565,17 @@
 }
 
 // -------------------- jit_function --------------------
-jit_function::jit_function () : module (0), llvm_function (0), mresult (0),
+jit_function::jit_function () : module (0), llvm_function (0),
+                                gccjit_function (),
+                                mresult (0),
                                 call_conv (jit_convention::length),
                                 mcan_error (false)
 {}
 
 jit_function::jit_function (llvm::Module *amodule,
+                            gccjit::context gccjit_ctxt,
                             jit_convention::type acall_conv,
-                            const llvm::Twine& aname, jit_type *aresult,
+                            std::string aname, jit_type *aresult,
                             const std::vector<jit_type *>& aargs)
   : module (amodule), mresult (aresult), args (aargs), call_conv (acall_conv),
     mcan_error (false)
@@ -613,17 +629,69 @@
 #else
     llvm_function->addFnAttr (llvm::Attribute::AlwaysInline);
 #endif
+
+    if (gccjit_ctxt.get_inner_context ())
+      {
+        std::vector<gccjit::param> gccjit_params;
+        for (int i = 0; i < args.size (); i++)
+          {
+            jit_type *ty = args[i];
+            assert (ty);
+
+            gccjit::type argty = ty->to_gccjit ();
+            if (ty->pointer_arg (call_conv))
+              argty = argty.get_pointer ();
+
+            std::stringstream paramname;
+            paramname << "arg" << i;
+
+            gccjit::param param = gccjit_ctxt.new_param (argty,
+                                                         paramname.str ());
+            gccjit_params.push_back (param);
+          }
+        gccjit::type gccjit_return_type;
+        if (aresult)
+          gccjit_return_type = aresult->to_gccjit ();
+        else
+          gccjit_return_type = gccjit_ctxt.get_type (GCC_JIT_TYPE_VOID);
+
+        enum gcc_jit_function_kind kind;
+        if (acall_conv == jit_convention::external)
+          kind = GCC_JIT_FUNCTION_IMPORTED;
+        else
+          {
+            if (0)
+              /* Doing this is correct, but makes the dump a little harder
+                 to read.
+                 Also, not fully implemented yet in libgccjit.  */
+              kind = GCC_JIT_FUNCTION_ALWAYS_INLINE;
+            else
+              kind = GCC_JIT_FUNCTION_EXPORTED;
+          }
+        gccjit_function =
+          gccjit_ctxt.new_function (kind,
+                                    gccjit_return_type,
+                                    aname,
+                                    gccjit_params,
+                                    0);
+      }
 }
 
 jit_function::jit_function (const jit_function& fn, jit_type *aresult,
                             const std::vector<jit_type *>& aargs)
-  : module (fn.module), llvm_function (fn.llvm_function), mresult (aresult),
+  : module (fn.module),
+    llvm_function (fn.llvm_function), 
+    gccjit_function (fn.gccjit_function),
+    mresult (aresult),
     args (aargs), call_conv (fn.call_conv), mcan_error (fn.mcan_error)
 {
 }
 
 jit_function::jit_function (const jit_function& fn)
-  : module (fn.module), llvm_function (fn.llvm_function), mresult (fn.mresult),
+  : module (fn.module),
+    llvm_function (fn.llvm_function), 
+    gccjit_function (fn.gccjit_function),
+    mresult (fn.mresult),
     args (fn.args), call_conv (fn.call_conv), mcan_error (fn.mcan_error)
 {}
 
@@ -781,8 +849,76 @@
 
   if (verify)
     llvm::verifyFunction (*llvm_function);
+
+  if (0)
+    {
+      std::cout << "-------------------- llvm ir (at do_return) --------------------";
+      std::cout << *llvm_function << std::endl;
+    }
 }
 
+#ifdef HAVE_GCCJIT
+#if 1
+gccjit::rvalue
+jit_function::call (gccjit::context ctxt,
+                    gccjit::block block,
+                    const std::vector<jit_value *>& in_args) const
+{
+  assert (in_args.size () == args.size ());
+  std::vector<gccjit::rvalue> gccjit_args (args.size ());
+  for (size_t i = 0; i < in_args.size (); ++i)
+    gccjit_args[i] = in_args[i]->as_rvalue ();
+  return call (ctxt, block, gccjit_args);
+}
+
+gccjit::rvalue
+jit_function::call (gccjit::context ctxt,
+                    gccjit::block block,
+                    std::vector<gccjit::rvalue>& in_args) const
+{
+  assert (in_args.size () == args.size ());
+
+#if 1
+  std::vector<gccjit::rvalue> packed_args (in_args.size ());
+
+  for (size_t i = 0; i < in_args.size (); ++i)
+    {
+      gccjit::rvalue arg = in_args[i];
+#if 0      
+      jit_type::convert_fn convert = args[i]->pack (call_conv);
+      if (convert)
+        arg = convert (builder, arg);
+#endif
+
+      if (args[i]->pointer_arg (call_conv))
+        {
+          // The LLVM implementation takes a copy using alloca, passing
+          // a ptr to the copy to the fn.  Emulate this behavior.
+          gccjit::lvalue tmp =
+            block.get_function ().new_local (arg.get_type (), "tmp");
+          block.add_assignment (tmp, arg);
+          arg = tmp.get_address ();
+        }
+
+      packed_args[i] = arg;
+    }
+
+  return ctxt.new_call (gccjit_function,
+                        packed_args);
+#else
+  return ctxt.new_call (gccjit_function,
+                        in_args);
+#endif
+}
+#endif
+
+gccjit::lvalue
+jit_function::argument (size_t idx) const
+{
+  return gccjit_function.get_param (idx);
+}
+#endif
+
 void
 jit_function::do_add_mapping (llvm::ExecutionEngine *engine, void *fn)
 {
@@ -955,6 +1091,7 @@
   return 0;
 }
 
+#ifdef HAVE_LLVM
 llvm::Value *
 jit_index_operation::create_arg_array (llvm::IRBuilderD& builder,
                                        const jit_function &fn, size_t start_idx,
@@ -974,6 +1111,28 @@
   builder.CreateStore (array, array_mem);
   return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ());
 }
+#endif // #ifdef HAVE_LLVM
+
+#ifdef HAVE_GCCJIT
+gccjit::rvalue
+jit_index_operation::create_arg_array (const jit_function &fn,
+                                       gccjit::block block,
+                                       size_t start_idx,
+                                       size_t end_idx) const
+{
+  size_t n = end_idx - start_idx;
+  gccjit::type scalar_t = jit_typeinfo::get_scalar_gccjit ();
+  gccjit::type array_t = block.get_context ().new_array_type (scalar_t, n);
+  gccjit::lvalue array =
+    block.get_function ().new_local (array_t, "tmp_array");
+  for (size_t i = start_idx; i < end_idx; ++i)
+    {
+      gccjit::rvalue idx = fn.argument (i);
+      block.add_assignment (array[i - start_idx], idx);
+    }
+  return array.get_address ().cast_to (scalar_t.get_pointer ());
+}
+#endif // #ifdef HAVE_GCCJIT
 
 // -------------------- jit_paren_subsref --------------------
 jit_function *
@@ -983,7 +1142,9 @@
   ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1);
 
   jit_type *scalar = jit_typeinfo::get_scalar ();
-  jit_function *fn = new jit_function (module, jit_convention::internal,
+  jit_function *fn = new jit_function (module,
+                                       gccjit_ctxt,
+                                       jit_convention::internal,
                                        ss.str (), scalar, types);
   fn->mark_can_error ();
   llvm::BasicBlock *body = fn->new_block ();
@@ -996,6 +1157,24 @@
   llvm::Value *mat = fn->argument (builder, 0);
   llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem);
   fn->do_return (builder, ret);
+
+  // gcc implementation
+  {
+    gccjit::function gf = fn->gccjit_function;
+    gccjit::block body = gf.new_block ();
+    gccjit::rvalue array = create_arg_array (*fn, body, 1, types.size ());
+    jit_type *index = jit_typeinfo::get_index ();
+    gccjit::rvalue nelem = gccjit_ctxt.new_rvalue (index->to_gccjit (),
+                                                   (int)types.size () - 1);
+    gccjit::rvalue mat = gf.get_param (0);
+    std::vector<gccjit::rvalue> args (3);
+    args[0] = mat;
+    args[1] = array;
+    args[2] = nelem;
+    gccjit::rvalue ret = paren_scalar.call (gccjit_ctxt, body, args);
+    body.end_with_return (ret);
+  }
+
   return fn;
 }
 
@@ -1008,7 +1187,9 @@
   types[2] = jit_typeinfo::get_index ();
 
   jit_type *scalar = jit_typeinfo::get_scalar ();
-  paren_scalar = jit_function (module, jit_convention::external,
+  paren_scalar = jit_function (module,
+                               gccjit_ctxt,
+                               jit_convention::external,
                                "octave_jit_paren_scalar", scalar, types);
   paren_scalar.add_mapping (engine, &octave_jit_paren_scalar);
   paren_scalar.mark_can_error ();
@@ -1022,7 +1203,9 @@
   ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2);
 
   jit_type *matrix = jit_typeinfo::get_matrix ();
-  jit_function *fn = new jit_function (module, jit_convention::internal,
+  jit_function *fn = new jit_function (module,
+                                       gccjit_ctxt,
+                                       jit_convention::internal,
                                        ss.str (), matrix, types);
   fn->mark_can_error ();
   llvm::BasicBlock *body = fn->new_block ();
@@ -1037,6 +1220,27 @@
   llvm::Value *value = fn->argument (builder, types.size () - 1);
   llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem, value);
   fn->do_return (builder, ret);
+
+  // gcc implementation
+  {
+    // FIXME: TODO
+    gccjit::function gf = fn->gccjit_function;
+    gccjit::block body = gf.new_block ();
+    gccjit::rvalue array = create_arg_array (*fn, body, 1, types.size () - 1);
+    jit_type *index = jit_typeinfo::get_index ();
+    gccjit::rvalue nelem = gccjit_ctxt.new_rvalue (index->to_gccjit (),
+                                                   (int)types.size () - 2);
+    gccjit::rvalue mat = gf.get_param (0);
+    gccjit::rvalue value = gf.get_param (types.size () - 1);
+    std::vector<gccjit::rvalue> args(4);
+    args[0] = mat;
+    args[1] = array;
+    args[2] = nelem;
+    args[3] = value;
+    gccjit::rvalue ret = paren_scalar.call (gccjit_ctxt, body, args);
+    body.end_with_return (ret);
+  }
+
   return fn;
 }
 
@@ -1053,7 +1257,9 @@
   types[2] = jit_typeinfo::get_index ();
   types[3] = jit_typeinfo::get_scalar ();
 
-  paren_scalar = jit_function (module, jit_convention::external,
+  paren_scalar = jit_function (module,
+                               gccjit_ctxt,
+                               jit_convention::external,
                                "octave_jit_paren_scalar", matrix, types);
   paren_scalar.add_mapping (engine, &octave_jit_paren_scalar_subsasgn);
   paren_scalar.mark_can_error ();
@@ -1075,7 +1281,12 @@
 {
   instance = this;
 
+#ifdef HAVE_GCCJIT
+  gccjit_ctxt = gccjit::context::acquire ();
+#endif
+
   // FIXME: We should be registering types like in octave_value_typeinfo
+#ifdef HAVE_LLVM
   llvm::Type *any_t = llvm::StructType::create (context, "octave_base_value");
   any_t = any_t->getPointerTo ();
 
@@ -1085,14 +1296,54 @@
   string_t = string_t->getPointerTo ();
   llvm::Type *index_t = llvm::Type::getIntNTy (context,
                                                sizeof(octave_idx_type) * 8);
-
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::type any_t_gcc =
+    gccjit_ctxt.new_opaque_struct_type ("octave_base_value");
+  any_t_gcc = any_t_gcc.get_pointer ();
+  gccjit::type scalar_t_gcc = gccjit_ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
+  gccjit::type bool_t_gcc = gccjit_ctxt.get_type (GCC_JIT_TYPE_BOOL);
+  gccjit::type string_t_gcc =
+    gccjit_ctxt.get_type (GCC_JIT_TYPE_CHAR).get_pointer ();
+  gccjit::type index_t_gcc = gccjit_ctxt.get_int_type <octave_idx_type> ();
+  gccjit::type int_t_gcc = gccjit_ctxt.get_type (GCC_JIT_TYPE_INT);
+#endif
+
+#ifdef HAVE_LLVM
   llvm::StructType *range_t = llvm::StructType::create (context, "range");
   std::vector<llvm::Type *> range_contents (4, scalar_t);
   range_contents[3] = index_t;
   range_t->setBody (range_contents);
-
+#endif
+#ifdef HAVE_GCCJIT
+  field_rng_base = gccjit_ctxt.new_field (scalar_t_gcc, "rng_base");
+  field_rng_limit = gccjit_ctxt.new_field (scalar_t_gcc, "rng_limit");
+  field_rng_inc = gccjit_ctxt.new_field (scalar_t_gcc, "rng_inc");
+  field_rng_nelem = gccjit_ctxt.new_field (index_t_gcc, "rng_nelem");
+  /* FIXME: what about the "mutable Matrix cache;" */
+
+  std::vector<gccjit::field> range_fields (4);
+  range_fields [0] = field_rng_base;
+  range_fields [1] = field_rng_limit;
+  range_fields [2] = field_rng_inc;
+  range_fields [3] = field_rng_nelem;
+
+  gccjit::type range_t_gcc =
+    gccjit_ctxt.new_struct_type (
+      "range",
+      range_fields,
+      gccjit_ctxt.new_location ("liboctave/array/Range.h", 33, 0));
+#endif
+
+#ifdef HAVE_LLVM
   llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8);
-
+#endif
+#ifdef HAVE_GCCJIT
+  gccjit::type refcount_t_gcc = gccjit_ctxt.get_type (GCC_JIT_TYPE_INT);
+#endif
+
+#ifdef HAVE_LLVM
   llvm::StructType *matrix_t = llvm::StructType::create (context, "matrix");
   llvm::Type *matrix_contents[5];
   matrix_contents[0] = refcount_t->getPointerTo ();
@@ -1101,8 +1352,58 @@
   matrix_contents[3] = index_t->getPointerTo ();
   matrix_contents[4] = string_t;
   matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5));
-
+#endif
+#ifdef HAVE_GCCJIT
+  /*
+    jit-typeinfo.h has, somewhat ominously:
+       // jit_array is compatable with the llvm array/matrix structures
+     typedef jit_array<NDArray, double> jit_matrix;
+  */
+  gccjit::type matrix_t_gcc;
+  {
+    /* typedef jit_array<NDArray, double> jit_matrix; */
+    /* template <typename T, typename U> struct jit_array {...}; */
+    gccjit::type T = string_t_gcc; /* NDArray */
+    gccjit::type U = scalar_t_gcc; /* double */
+
+    /* int *ref_count; */
+    field_ref_count =
+      gccjit_ctxt.new_field (refcount_t_gcc.get_pointer (), "ref_count");
+
+    /* U *slice_data; */
+    field_slice_data =
+      gccjit_ctxt.new_field (U.get_pointer (), "slice_data");
+
+    /* octave_idx_type slice_len; */
+    field_slice_len = gccjit_ctxt.new_field (index_t_gcc, "slice_len");
+
+    /* octave_idx_type *dimensions; */
+    field_dimensions =
+      gccjit_ctxt.new_field (index_t_gcc.get_pointer (), "dimensions");
+
+    /* T *array; */
+    field_array = gccjit_ctxt.new_field (T.get_pointer (), "array");
+
+    std::vector<gccjit::field> matrix_fields (5);
+    matrix_fields[0] = field_ref_count;
+    matrix_fields[1] = field_slice_data;
+    matrix_fields[2] = field_slice_len;
+    matrix_fields[3] = field_dimensions;
+    matrix_fields[4] = field_array;
+
+    matrix_t_gcc = gccjit_ctxt.new_struct_type (
+      "jit_matrix",
+      matrix_fields,
+      gccjit_ctxt.new_location ("jit-typeinfo.h", 106, 0));
+  }
+#endif
+
+#ifdef HAVE_LLVM
   llvm::Type *complex_t = llvm::ArrayType::get (scalar_t, 2);
+#endif
+#ifdef HAVE_GCCJIT
+  gccjit::type complex_t_gcc = gccjit_ctxt.new_array_type (scalar_t_gcc, 2);
+#endif
 
   // complex_ret is what is passed to C functions in order to get calling
   // convention right
@@ -1116,16 +1417,18 @@
   }
 
   // create types
-  any = new_type ("any", 0, any_t);
-  matrix = new_type ("matrix", any, matrix_t);
-  complex = new_type ("complex", any, complex_t);
-  scalar = new_type ("scalar", complex, scalar_t);
-  scalar_ptr = new_type ("scalar_ptr", 0, scalar_t->getPointerTo ());
-  any_ptr = new_type ("any_ptr", 0, any_t->getPointerTo ());
-  range = new_type ("range", any, range_t);
-  string = new_type ("string", any, string_t);
-  boolean = new_type ("bool", any, bool_t);
-  index = new_type ("index", any, index_t);
+  any = new_type ("any", 0, any_t, any_t_gcc);
+  matrix = new_type ("matrix", any, matrix_t, matrix_t_gcc);
+  complex = new_type ("complex", any, complex_t, complex_t_gcc);
+  scalar = new_type ("scalar", complex, scalar_t, scalar_t_gcc);
+  scalar_ptr = new_type ("scalar_ptr", 0, scalar_t->getPointerTo (),
+    scalar_t_gcc.get_pointer ());
+  any_ptr = new_type ("any_ptr", 0, any_t->getPointerTo (),
+    any_t_gcc.get_pointer());
+  range = new_type ("range", any, range_t, range_t_gcc);
+  string = new_type ("string", any, string_t, string_t_gcc);
+  boolean = new_type ("bool", any, bool_t, bool_t_gcc);
+  index = new_type ("index", any, index_t, index_t_gcc);
 
   create_int (8);
   create_int (16);
@@ -1151,10 +1454,11 @@
   if (sizeof (void *) == 4)
     complex->mark_sret (jit_convention::external);
 
-  paren_subsref_fn.initialize (module, engine);
-  paren_subsasgn_fn.initialize (module, engine);
+  paren_subsref_fn.initialize (module, engine, gccjit_ctxt);
+  paren_subsasgn_fn.initialize (module, engine, gccjit_ctxt);
 
   // bind global variables
+#ifdef HAVE_LLVM
   lerror_state = new llvm::GlobalVariable (*module, bool_t, false,
                                            llvm::GlobalValue::ExternalLinkage,
                                            0, "error_state");
@@ -1169,6 +1473,20 @@
                                 "octave_interrupt_state");
   engine->addGlobalMapping (loctave_interrupt_state,
                             reinterpret_cast<void *> (&octave_interrupt_state));
+#endif
+
+#ifdef HAVE_GCCJIT
+  // Access "error_state" (actually declared as an "int"), by
+  // taking its address and dereferencing:
+  error_state_gccjit =
+    *gccjit_ctxt.new_rvalue (int_t_gcc.get_pointer (),
+                             &error_state);
+  sig_atomic_type_gccjit = gccjit_ctxt.get_int_type <sig_atomic_t> ();
+  octave_interrupt_state_gccjit =
+    *gccjit_ctxt.new_rvalue (
+      sig_atomic_type_gccjit.get_volatile ().get_pointer (),
+        &octave_interrupt_state);
+#endif
 
   // generic call function
   {
@@ -1202,8 +1520,10 @@
 
   for (int op = 0; op < octave_value::num_binary_ops; ++op)
     {
-      llvm::Twine fn_name ("octave_jit_binary_any_any_");
-      fn_name = fn_name + llvm::Twine (op);
+      std::string fn_name ("octave_jit_binary_any_any_");
+      char buf[64];
+      snprintf (buf, sizeof(buf), "%i", op);
+      fn_name = fn_name + std::string (buf);
 
       fn = create_internal (fn_name, any, any, any);
       fn.mark_can_error ();
@@ -1216,6 +1536,18 @@
                                           fn.argument (builder, 0),
                                           fn.argument (builder, 1));
       fn.do_return (builder, ret);
+
+      // gccjit implementation of octave_jit_binary_any_any_*:
+      gccjit::function gf = fn.gccjit_function;
+      gccjit::block gccjit_block = gf.new_block ();
+      gccjit_block.end_with_return (
+        gccjit_block.add_call (
+          any_binary.gccjit_function,
+          gccjit_ctxt.new_rvalue (binary_op_type->to_gccjit (),
+                                  op),
+          gf.get_param (0),
+          gf.get_param (1)));
+                                     
       binary_ops[op].add_overload (fn);
     }
 
@@ -1247,20 +1579,38 @@
   destroy_fn.add_overload (create_identity(index));
   destroy_fn.add_overload (create_identity(complex));
 
-  // -------------------- scalar related operations --------------------
-
   // now for binary scalar operations
-  add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd);
-  add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub);
-  add_binary_op (scalar, octave_value::op_mul, llvm::Instruction::FMul);
-  add_binary_op (scalar, octave_value::op_el_mul, llvm::Instruction::FMul);
-
-  add_binary_fcmp (scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT);
-  add_binary_fcmp (scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE);
-  add_binary_fcmp (scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ);
-  add_binary_fcmp (scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE);
-  add_binary_fcmp (scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT);
-  add_binary_fcmp (scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE);
+  add_binary_op (scalar, octave_value::op_add,
+                 llvm::Instruction::FAdd,
+                 GCC_JIT_BINARY_OP_PLUS);
+  add_binary_op (scalar, octave_value::op_sub,
+                 llvm::Instruction::FSub,
+                 GCC_JIT_BINARY_OP_MINUS);
+  add_binary_op (scalar, octave_value::op_mul,
+                 llvm::Instruction::FMul,
+                 GCC_JIT_BINARY_OP_MULT);
+  add_binary_op (scalar, octave_value::op_el_mul,
+                 llvm::Instruction::FMul,
+                 GCC_JIT_BINARY_OP_MULT);
+
+  add_binary_fcmp (scalar, octave_value::op_lt,
+                   llvm::CmpInst::FCMP_ULT,
+                   GCC_JIT_COMPARISON_LT);
+  add_binary_fcmp (scalar, octave_value::op_le,
+                   llvm::CmpInst::FCMP_ULE,
+                   GCC_JIT_COMPARISON_LE);
+  add_binary_fcmp (scalar, octave_value::op_eq,
+                   llvm::CmpInst::FCMP_UEQ,
+                   GCC_JIT_COMPARISON_EQ);
+  add_binary_fcmp (scalar, octave_value::op_ge,
+                   llvm::CmpInst::FCMP_UGE,
+                   GCC_JIT_COMPARISON_GE);
+  add_binary_fcmp (scalar, octave_value::op_gt,
+                   llvm::CmpInst::FCMP_UGT,
+                   GCC_JIT_COMPARISON_GT);
+  add_binary_fcmp (scalar, octave_value::op_ne,
+                   llvm::CmpInst::FCMP_UNE,
+                   GCC_JIT_COMPARISON_NE);
 
   jit_function gripe_div0 = create_external (JIT_FN (gripe_divide_by_zero), 0);
   gripe_div0.mark_can_error ();
@@ -1288,6 +1638,22 @@
                                            fn.argument (builder, 1));
     fn.do_return (builder, ret);
   }
+  // gccjit implementation of octave_jit_div_scalar_scalar:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block initial_block = gf.new_block ("initial");
+    gccjit::block warn_block = gf.new_block ("warn");
+    gccjit::block normal_block = gf.new_block ("normal");
+    initial_block.end_with_conditional (
+      gf.get_param (1) != scalar_t_gcc.zero (),
+      normal_block, // on_true
+      warn_block); // on_false
+
+    warn_block.add_call (gripe_div0.gccjit_function);
+    warn_block.end_with_jump (normal_block);
+
+    normal_block.end_with_return (gf.get_param (0) / gf.get_param (1));
+  }
   binary_ops[octave_value::op_div].add_overload (fn);
   binary_ops[octave_value::op_el_div].add_overload (fn);
 
@@ -1306,7 +1672,7 @@
 
   // now for unary scalar operations
   // FIXME: Impelment not
-  fn = create_internal ("octave_jit_++", scalar, scalar);
+  fn = create_internal ("octave_jit_plusplus", scalar, scalar);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
   {
@@ -1315,9 +1681,15 @@
     val = builder.CreateFAdd (val, one);
     fn.do_return (builder, val);
   }
+  // gccjit implementation of octave_jit_plusplus:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (gf.get_param (0) + scalar_t_gcc.one ());
+  }
   unary_ops[octave_value::op_incr].add_overload (fn);
 
-  fn = create_internal ("octave_jit_--", scalar, scalar);
+  fn = create_internal ("octave_jit_minusminus", scalar, scalar);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
   {
@@ -1325,6 +1697,11 @@
     llvm::Value *val = fn.argument (builder, 0);
     val = builder.CreateFSub (val, one);
     fn.do_return (builder, val);
+
+    // gccjit implementation of octave_jit_minusminus:
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (gf.get_param (0) - scalar_t_gcc.one ());
   }
   unary_ops[octave_value::op_decr].add_overload (fn);
 
@@ -1337,7 +1714,12 @@
     val = builder.CreateFMul (val, mone);
     fn.do_return (builder, val);
   }
-  unary_ops[octave_value::op_uminus].add_overload (fn);
+  // gccjit implementation of octave_jit_uminus:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (-gf.get_param (0));
+  }
 
   fn = create_identity (scalar);
   unary_ops[octave_value::op_uplus].add_overload (fn);
@@ -1345,7 +1727,7 @@
   unary_ops[octave_value::op_hermitian].add_overload (fn);
 
   // now for binary complex operations
-  fn = create_internal ("octave_jit_+_complex_complex", complex, complex,
+  fn = create_internal ("octave_jit_plus_complex_complex", complex, complex,
                         complex);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
@@ -1358,9 +1740,19 @@
                                             complex_imag (rhs));
     fn.do_return (builder, complex_new (real, imag));
   }
+  // gccjit implementation of octave_jit_plus_complex_complex:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue lhs = gf.get_param (0);
+    gccjit::rvalue rhs = gf.get_param (1);
+    gccjit::rvalue real = complex_real (lhs) + complex_real (rhs);
+    gccjit::rvalue imag = complex_imag (lhs) + complex_imag (rhs);
+    b.end_with_return (complex_new (b, real, imag));
+  }
   binary_ops[octave_value::op_add].add_overload (fn);
 
-  fn = create_internal ("octave_jit_-_complex_complex", complex, complex,
+  fn = create_internal ("octave_jit_minus_complex_complex", complex, complex,
                         complex);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
@@ -1373,6 +1765,16 @@
                                             complex_imag (rhs));
     fn.do_return (builder, complex_new (real, imag));
   }
+  // gccjit implementation of octave_jit_minus_complex_complex:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue lhs = gf.get_param (0);
+    gccjit::rvalue rhs = gf.get_param (1);
+    gccjit::rvalue real = complex_real (lhs) - complex_real (rhs);
+    gccjit::rvalue imag = complex_imag (lhs) - complex_imag (rhs);
+    b.end_with_return (complex_new (b, real, imag));
+  }
   binary_ops[octave_value::op_sub].add_overload (fn);
 
   fn = create_external (JIT_FN (octave_jit_complex_mul),
@@ -1391,7 +1793,7 @@
   binary_ops[octave_value::op_pow].add_overload (fn);
   binary_ops[octave_value::op_el_pow].add_overload (fn);
 
-  fn = create_internal ("octave_jit_*_scalar_complex", complex, scalar,
+  fn = create_internal ("octave_jit_mult_scalar_complex", complex, scalar,
                         complex);
   jit_function mul_scalar_complex = fn;
   body = fn.new_block ();
@@ -1418,6 +1820,29 @@
                         builder.CreateFMul (lhs, complex_imag (rhs)));
     fn.do_return (builder, temp);
   }
+  // gccjit implementation of octave_jit_mult_scalar_complex:
+  {
+    gccjit::function gf = fn.gccjit_function;
+
+    gccjit::rvalue fzero = scalar_t_gcc.zero ();
+    gccjit::rvalue lhs = gf.get_param (0);
+    gccjit::rvalue rhs = gf.get_param (1);
+
+    gccjit::block initial = gf.new_block ("initial");
+    gccjit::block complex_mul = gf.new_block ("complex_mul");
+    gccjit::block scalar_mul = gf.new_block ("scalar_mul");
+
+    initial.end_with_conditional (complex_imag (rhs) == fzero,
+                                  scalar_mul,
+                                  complex_mul);
+
+    scalar_mul.end_with_return (complex_new (scalar_mul,
+                                             lhs * complex_real (rhs),
+                                             fzero));
+    complex_mul.end_with_return (complex_new (complex_mul,
+                                              lhs * complex_real (rhs),
+                                              lhs * complex_imag (rhs)));
+  }
   binary_ops[octave_value::op_mul].add_overload (fn);
   binary_ops[octave_value::op_el_mul].add_overload (fn);
 
@@ -1426,7 +1851,7 @@
   binary_ops[octave_value::op_mul].add_overload (fn);
   binary_ops[octave_value::op_el_mul].add_overload (fn);
 
-  fn = create_internal ("octave_jit_+_scalar_complex", complex, scalar,
+  fn = create_internal ("octave_jit_plus_scalar_complex", complex, scalar,
                         complex);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
@@ -1436,12 +1861,21 @@
     llvm::Value *real = builder.CreateFAdd (lhs, complex_real (rhs));
     fn.do_return (builder, complex_real (rhs, real));
   }
+  // gccjit implementation of octave_jit_plus_scalar_complex:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue lhs = gf.get_param (0);
+    gccjit::lvalue rhs = gf.get_param (1);
+    gccjit::rvalue real = lhs + complex_real (rhs);
+    b.end_with_return (complex_real (b, rhs, real));
+  }
   binary_ops[octave_value::op_add].add_overload (fn);
 
   fn = mirror_binary (fn);
   binary_ops[octave_value::op_add].add_overload (fn);
 
-  fn = create_internal ("octave_jit_-_complex_scalar", complex, complex,
+  fn = create_internal ("octave_jit_minus_complex_scalar", complex, complex,
                         scalar);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
@@ -1451,9 +1885,18 @@
     llvm::Value *real = builder.CreateFSub (complex_real (lhs), rhs);
     fn.do_return (builder, complex_real (lhs, real));
   }
+  // gccjit implementation of octave_jit_minus_complex_scalar:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::lvalue lhs = gf.get_param (0);
+    gccjit::rvalue rhs = gf.get_param (1);
+    gccjit::rvalue real = complex_real (lhs) - rhs;
+    b.end_with_return (complex_real (b, lhs, real));
+  }
   binary_ops[octave_value::op_sub].add_overload (fn);
 
-  fn = create_internal ("octave_jit_-_scalar_complex", complex, scalar,
+  fn = create_internal ("octave_jit_minus_scalar_complex", complex, scalar,
                         complex);
   body = fn.new_block ();
   builder.SetInsertPoint (body);
@@ -1463,6 +1906,15 @@
     llvm::Value *real = builder.CreateFSub (lhs, complex_real (rhs));
     fn.do_return (builder, complex_real (rhs, real));
   }
+  // gccjit implementation of octave_jit_minus_scalar_complex:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue lhs = gf.get_param (0);
+    gccjit::lvalue rhs = gf.get_param (1);
+    gccjit::rvalue real = lhs - complex_real (rhs);
+    b.end_with_return (complex_real (b, rhs, real));
+  }
   binary_ops[octave_value::op_sub].add_overload (fn);
 
   fn = create_external (JIT_FN (octave_jit_pow_scalar_complex), complex, scalar,
@@ -1476,11 +1928,17 @@
   binary_ops[octave_value::op_el_pow].add_overload (fn);
 
   // now for binary index operators
-  add_binary_op (index, octave_value::op_add, llvm::Instruction::Add);
+  add_binary_op (index, octave_value::op_add,
+                 llvm::Instruction::Add,
+                 GCC_JIT_BINARY_OP_PLUS);
 
   // and binary bool operators
-  add_binary_op (boolean, octave_value::op_el_or, llvm::Instruction::Or);
-  add_binary_op (boolean, octave_value::op_el_and, llvm::Instruction::And);
+  add_binary_op (boolean, octave_value::op_el_or,
+                 llvm::Instruction::Or,
+                 GCC_JIT_BINARY_OP_LOGICAL_OR);
+  add_binary_op (boolean, octave_value::op_el_and,
+                 llvm::Instruction::And,
+                 GCC_JIT_BINARY_OP_LOGICAL_AND);
 
   // now for printing functions
   print_fn.stash_name ("print");
@@ -1497,6 +1955,11 @@
     llvm::Value *zero = llvm::ConstantInt::get (index_t, 0);
     fn.do_return (builder, zero);
   }
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (gccjit_ctxt.zero (index_t_gcc));
+  }
   for_init_fn.add_overload (fn);
 
   // bounds check for for loop
@@ -1511,6 +1974,17 @@
     llvm::Value *idx = fn.argument (builder, 1);
     llvm::Value *ret = builder.CreateICmpULT (idx, nelem);
     fn.do_return (builder, ret);
+
+  }
+  {
+    gccjit::function gf = fn.gccjit_function;
+    // FIXME: is "range" a (struct range) or a (struct range *) ?
+    gccjit::rvalue nelem
+      = gf.get_param (0).access_field (field_rng_nelem);
+    gccjit::rvalue idx = gf.get_param (1);
+    gccjit::rvalue ret = idx < nelem;
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (ret);
   }
   for_check_fn.add_overload (fn);
 
@@ -1531,6 +2005,18 @@
     ret = builder.CreateFAdd (base, ret);
     fn.do_return (builder, ret);
   }
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue idx = gf.get_param (1);
+    gccjit::rvalue didx = idx.cast_to (scalar_t_gcc);
+    gccjit::rvalue rng = gf.get_param (0);
+    gccjit::rvalue base = rng.access_field (field_rng_base);
+    gccjit::rvalue inc = rng.access_field (field_rng_inc);
+    gccjit::rvalue ret = didx * inc;
+    ret = base + ret;
+    b.end_with_return (ret);
+  }
   for_index_fn.add_overload (fn);
 
   // logically true
@@ -1562,6 +2048,20 @@
     llvm::Value *ret = builder.CreateFCmpONE (fn.argument (builder, 0), zero);
     fn.do_return (builder, ret);
   }
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block initial = gf.new_block ("initial");
+    gccjit::block error = gf.new_block ("error");
+    gccjit::block normal = gf.new_block ("normal");
+    initial.add_comment ("check for NaN");
+    initial.end_with_conditional (gf.get_param (0) != gf.get_param (0),
+                                  error, normal);
+
+    error.add_call (gripe_nantl.gccjit_function);
+    error.end_with_jump (normal);
+    
+    normal.end_with_return ( gf.get_param (0) != scalar_t_gcc.zero ());
+  }
   logically_true_fn.add_overload (fn);
 
   // logically_true boolean
@@ -1595,6 +2095,20 @@
     rng = builder.CreateInsertValue (rng, nelem, 3);
     fn.do_return (builder, rng);
   }
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::rvalue base = gf.get_param (0);
+    gccjit::rvalue limit = gf.get_param (1);
+    gccjit::rvalue inc = gf.get_param (2);
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue nelem = compute_nelem.gccjit_function (base, limit, inc);
+    gccjit::lvalue rng = gf.new_local (range_t_gcc, "rng");
+    b.add_assignment (rng.access_field (field_rng_base), base);
+    b.add_assignment (rng.access_field (field_rng_limit), limit);
+    b.add_assignment (rng.access_field (field_rng_inc), inc);
+    b.add_assignment (rng.access_field (field_rng_nelem), nelem);
+    b.end_with_return (rng);
+  }
   make_range_fn.add_overload (fn);
 
   // paren_subsref
@@ -1606,7 +2120,7 @@
                                                0, jit_int, jit_int, index,
                                                index);
 
-  fn = create_internal ("()subsref", scalar, matrix, scalar);
+  fn = create_internal ("subsref", scalar, matrix, scalar);
   fn.mark_can_error ();
 
   body = fn.new_block ();
@@ -1665,10 +2179,53 @@
     merge->addIncoming (ret, success);
     fn.do_return (builder, merge);
   }
+  // gccjit implementation of subsref:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block initial = gf.new_block ("initial");
+
+    gccjit::rvalue one_idx = index_t_gcc.one ();
+    gccjit::rvalue one_int = jit_int->to_gccjit ().one ();
+
+    gccjit::rvalue mat = gf.get_param (0);
+    gccjit::rvalue idx = gf.get_param (1); // scalar
+
+    // convert index to scalar to integer, and check index >= 1
+    gccjit::rvalue int_idx = idx.cast_to (index_t_gcc);
+    gccjit::rvalue check_idx = int_idx.cast_to (scalar_t_gcc);
+    gccjit::rvalue cond0 = (idx != check_idx);
+    gccjit::rvalue cond1 = (int_idx < one_idx);
+
+    gccjit::block conv_error = gf.new_block ("conv_error");
+    gccjit::block normal = gf.new_block ("normal");
+    initial.end_with_conditional (cond0 || cond1, conv_error, normal);
+
+    // "conv_error" block:
+    conv_error.add_call (ginvalid_index.gccjit_function);
+    conv_error.end_with_return (scalar_t_gcc.zero ()); // dummy value
+
+    // "normal" block:
+    gccjit::rvalue len = mat.access_field (field_slice_len);
+    gccjit::rvalue cond = (int_idx > len);
+    gccjit::block bounds_error = gf.new_block ("bounds_error");
+    gccjit::block success = gf.new_block ("success");
+    normal.end_with_conditional (cond, bounds_error, success);
+
+    // "bounds_error" block:
+    bounds_error.add_call (gindex_range.gccjit_function,
+                           one_int, one_int, int_idx, len);
+    bounds_error.end_with_return (scalar_t_gcc.zero ()); // dummy value
+
+    // "success" block:
+    gccjit::rvalue data = mat.access_field (field_slice_data);
+    gccjit::rvalue gep = data[int_idx];
+    gccjit::rvalue ret = gep;
+    success.end_with_return (ret);
+  }
   paren_subsref_fn.add_overload (fn);
 
   // paren subsasgn
-  paren_subsasgn_fn.stash_name ("()subsasgn");
+  paren_subsasgn_fn.stash_name ("subsasgn");
 
   jit_function resize_paren_subsasgn
     = create_external (JIT_FN (octave_jit_paren_subsasgn_impl), matrix, matrix,
@@ -1737,6 +2294,59 @@
     merge->addIncoming (mat, success);
     fn.do_return (builder, merge);
   }
+  // gccjit implementation of octave_jit_paren_subsasgn:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block initial = gf.new_block ("initial");
+    gccjit::rvalue one_idx = index_t_gcc.one ();
+    gccjit::rvalue one_int = jit_int->to_gccjit ().one ();
+
+    gccjit::lvalue mat = gf.get_param (0);
+    gccjit::rvalue idx = gf.get_param (1);
+    gccjit::rvalue value = gf.get_param (2);
+    gccjit::rvalue int_idx = idx.cast_to (index_t_gcc);
+    gccjit::rvalue check_idx = int_idx.cast_to (scalar_t_gcc);
+    gccjit::rvalue cond0 = (idx != check_idx);
+    gccjit::rvalue cond1 = (int_idx < one_idx);
+    gccjit::rvalue cond = (cond0 || cond1);
+
+    gccjit::block conv_error = gf.new_block ("conv_error");
+    gccjit::block normal = gf.new_block ("normal");
+    initial.end_with_conditional (cond, conv_error, normal);
+
+    // block: conv_error
+    conv_error.add_call (ginvalid_index.gccjit_function);
+    conv_error.end_with_return (mat);
+
+    // block: normal
+    gccjit::rvalue len = mat.access_field (field_slice_len);
+    cond0 = (int_idx > len);
+
+    gccjit::rvalue rcount = mat.access_field (field_ref_count);
+    rcount = rcount.dereference ();
+    cond1 = rcount > one_int;
+    cond = (cond0 || cond1);
+
+    gccjit::block bounds_error = gf.new_block ("bounds_error");
+    gccjit::block success = gf.new_block ("success");
+    normal.end_with_conditional (cond, bounds_error, success);
+
+    // block: bounds_error
+    // resize on out of bounds access
+    std::vector<gccjit::rvalue> args (3);
+    args[0] = mat;
+    args[1] = int_idx;
+    args[2] = value;
+    gccjit::rvalue resize_result =
+      resize_paren_subsasgn.call (gccjit_ctxt, bounds_error, args);
+    bounds_error.end_with_return (resize_result);
+
+    // block: success
+    gccjit::rvalue data = mat.access_field (field_slice_data);
+    gccjit::lvalue gep = data[int_idx];
+    success.add_assignment (gep, value);
+    success.end_with_return (mat);
+  }
   paren_subsasgn_fn.add_overload (fn);
 
   fn = create_external (JIT_FN (octave_jit_paren_subsasgn_matrix_range), matrix,
@@ -1753,6 +2363,14 @@
     llvm::Value *ret = builder.CreateExtractValue (mat, 2);
     fn.do_return (builder, builder.CreateSIToFP (ret, scalar_t));
   }
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::rvalue mat = gf.get_param (0);
+    // FIXME: is this the right behavior?
+    gccjit::rvalue ret = mat.access_field (field_slice_len);
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (ret.cast_to (scalar_t_gcc));
+  }
   end1_fn.add_overload (fn);
 
   end_fn.stash_name ("end");
@@ -1811,6 +2429,13 @@
     llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
     fn.do_return (builder, complex_new (fn.argument (builder, 0), zero));
   }
+  // gccjit implementation of octave_jit_cast_complex_scalar:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    gccjit::rvalue zero = scalar_t_gcc.zero ();
+    b.end_with_return (complex_new (b, gf.get_param (0), zero));
+  }
   casts[complex->type_id ()].add_overload (fn);
 
   // cast scalar <- complex
@@ -1818,6 +2443,11 @@
   body = fn.new_block ();
   builder.SetInsertPoint (body);
   fn.do_return (builder, complex_real (fn.argument (builder, 0)));
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (complex_real (gf.get_param (0)));
+  }
   casts[scalar->type_id ()].add_overload (fn);
 
   // cast any <- any
@@ -1845,7 +2475,9 @@
   register_generic ("cos", matrix, matrix);
 
   add_builtin ("exp");
-  register_intrinsic ("exp", llvm::Intrinsic::exp, scalar, scalar);
+  // FIXME: looks like a typo: "cos" here should be "exp":
+  // filed as http://savannah.gnu.org/bugs/index.php?41560
+  register_intrinsic ("exp", llvm::Intrinsic::cos, scalar, scalar);
   register_generic ("exp", matrix, matrix);
 
   add_builtin ("balance");
@@ -1860,10 +2492,13 @@
   add_builtin ("norm");
   register_generic ("norm", scalar, matrix);
 
+  //FIXME: gccjit can't yet cope with duplicate names
+#if 0
   add_builtin ("rand");
   register_generic ("rand", matrix, scalar);
   register_generic ("rand", matrix, std::vector<jit_type *> (2, scalar));
 
+
   add_builtin ("magic");
   register_generic ("magic", matrix, scalar);
   register_generic ("magic", matrix, std::vector<jit_type *> (2, scalar));
@@ -1871,6 +2506,7 @@
   add_builtin ("eye");
   register_generic ("eye", matrix, scalar);
   register_generic ("eye", matrix, std::vector<jit_type *> (2, scalar));
+#endif
 
   add_builtin ("mod");
   register_generic ("mod", scalar, std::vector<jit_type *> (2, scalar));
@@ -1897,6 +2533,8 @@
       casts[btype->type_id ()].add_overload (jit_function (any_id, btype,
                                                            args));
     }
+
+  gccjit_ctxt.dump_to_file ("/tmp/jit-typeinfo-dump.c", true);
 }
 
 const jit_function&
@@ -1910,10 +2548,23 @@
 }
 
 jit_type*
-jit_typeinfo::new_type (const std::string& name, jit_type *parent,
-                        llvm::Type *llvm_type, bool skip_paren)
+jit_typeinfo::new_type (const std::string& name, jit_type *parent
+#ifdef HAVE_LLVM
+                        , llvm::Type *llvm_type
+#endif
+#ifdef HAVE_GCCJIT
+                        , gccjit::type gccjit_type
+#endif
+                        , bool skip_paren)
 {
-  jit_type *ret = new jit_type (name, parent, llvm_type, skip_paren, next_id++);
+  jit_type *ret = new jit_type (name, parent
+#ifdef HAVE_LLVM
+                        , llvm_type
+#endif
+#ifdef HAVE_GCCJIT
+                        , gccjit_type
+#endif
+                                , skip_paren, next_id++);
   id_to_type.push_back (ret);
   return ret;
 }
@@ -1930,14 +2581,18 @@
 
 // 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)
+jit_typeinfo::add_binary_op (jit_type *ty, int op,
+                             int llvm_op,
+                             enum gcc_jit_binary_op gccjit_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)
+  fname << "octave_jit_" << octave_value::binary_op_fcn_name (ov_op)
         << "_" << ty->name ();
 
   jit_function fn = create_internal (fname.str (), ty, ty, ty);
+
+  // LLVM implementation:
   llvm::BasicBlock *block = fn.new_block ();
   builder.SetInsertPoint (block);
   llvm::Instruction::BinaryOps temp
@@ -1946,18 +2601,33 @@
   llvm::Value *ret = builder.CreateBinOp (temp, fn.argument (builder, 0),
                                           fn.argument (builder, 1));
   fn.do_return (builder, ret);
+
+  // gccjit implementation:
+  gccjit::function gf = fn.gccjit_function;
+  gccjit::block b = gf.new_block ();
+  b.end_with_return (
+    gf.get_context ().new_binary_op (
+      gccjit_op,
+      ty->to_gccjit (),
+      gf.get_param (0),
+      gf.get_param (1)));                              
+
   binary_ops[op].add_overload (fn);
 }
 
 void
-jit_typeinfo::add_binary_icmp (jit_type *ty, int op, int llvm_op)
+jit_typeinfo::add_binary_icmp (jit_type *ty, int op,
+                               int llvm_op,
+                               enum gcc_jit_comparison gccjit_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)
+  fname << "octave_jit_" << octave_value::binary_op_fcn_name (ov_op)
         << "_" << ty->name ();
 
   jit_function fn = create_internal (fname.str (), boolean, ty, ty);
+
+  // LLVM implementation:
   llvm::BasicBlock *block = fn.new_block ();
   builder.SetInsertPoint (block);
   llvm::CmpInst::Predicate temp
@@ -1965,18 +2635,32 @@
   llvm::Value *ret = builder.CreateICmp (temp, fn.argument (builder, 0),
                                          fn.argument (builder, 1));
   fn.do_return (builder, ret);
+
+  // gccjit implementation:
+  gccjit::function gf = fn.gccjit_function;
+  gccjit::block b = gf.new_block ();
+  b.end_with_return (
+    gf.get_context ().new_comparison (
+      gccjit_op,
+      gf.get_param (0),
+      gf.get_param (1)));                              
+
   binary_ops[op].add_overload (fn);
 }
 
 void
-jit_typeinfo::add_binary_fcmp (jit_type *ty, int op, int llvm_op)
+jit_typeinfo::add_binary_fcmp (jit_type *ty, int op,
+                               int llvm_op,
+                               enum gcc_jit_comparison gccjit_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)
+  fname << "octave_jit_" << octave_value::binary_op_fcn_name (ov_op)
         << "_" << ty->name ();
 
   jit_function fn = create_internal (fname.str (), boolean, ty, ty);
+
+  // LLVM implementation:
   llvm::BasicBlock *block = fn.new_block ();
   builder.SetInsertPoint (block);
   llvm::CmpInst::Predicate temp
@@ -1984,15 +2668,25 @@
   llvm::Value *ret = builder.CreateFCmp (temp, fn.argument (builder, 0),
                                          fn.argument (builder, 1));
   fn.do_return (builder, ret);
+
+  // gccjit implementation:
+  gccjit::function gf = fn.gccjit_function;
+  gccjit::block b = gf.new_block ();
+  b.end_with_return (
+    gf.get_context ().new_comparison (
+      gccjit_op,
+      gf.get_param (0),
+      gf.get_param (1)));                              
+
   binary_ops[op].add_overload (fn);
 }
 
 jit_function
-jit_typeinfo::create_function (jit_convention::type cc, const llvm::Twine& name,
+jit_typeinfo::create_function (jit_convention::type cc, std::string name,
                                jit_type *ret,
                                const std::vector<jit_type *>& args)
 {
-  jit_function result (module, cc, name, ret, args);
+  jit_function result (module, gccjit_ctxt, cc, name, ret, args);
   return result;
 }
 
@@ -2009,15 +2703,24 @@
       name << "id_" << type->name ();
 
       jit_function fn = create_internal (name.str (), type, type);
+
+      // LLVM implementation:
       llvm::BasicBlock *body = fn.new_block ();
       builder.SetInsertPoint (body);
       fn.do_return (builder, fn.argument (builder, 0));
+
+       // gccjit implementation:
+      gccjit::function gf = fn.gccjit_function;
+      gccjit::block b = gf.new_block ();
+      b.end_with_return (gf.get_param (0));
+
       return identities[id] = fn;
     }
 
   return identities[id];
 }
 
+#ifdef HAVE_LLVM
 llvm::Value *
 jit_typeinfo::do_insert_error_check (llvm::IRBuilderD& abuilder)
 {
@@ -2031,11 +2734,27 @@
   val->setVolatile (true);
   return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0));
 }
+#endif /* #ifdef HAVE_LLVM */
+
+#ifdef HAVE_GCCJIT
+gccjit::rvalue
+jit_typeinfo::do_insert_error_check (gccjit::function func)
+{
+  return error_state_gccjit.cast_to (gccjit_ctxt.get_type (GCC_JIT_TYPE_BOOL));
+}
+
+gccjit::rvalue
+jit_typeinfo::do_insert_interrupt_check (gccjit::function func)
+{
+  return octave_interrupt_state_gccjit > sig_atomic_type_gccjit.zero ();
+}
+#endif /* #ifdef HAVE_GCCJIT */
+
 
 void
 jit_typeinfo::add_builtin (const std::string& name)
 {
-  jit_type *btype = new_type (name, any, any->to_llvm (), true);
+  jit_type *btype = new_type (name, any, any->to_llvm (), any->to_gccjit (), true);
   builtins[name] = btype;
 
   octave_builtin *ov_builtin = find_builtin (name);
@@ -2077,6 +2796,19 @@
 
   llvm::Value *ret = builder.CreateCall (ifun, fargs);
   fn.do_return (builder, ret);
+
+  // gcc implementation
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::function builtin = gccjit_ctxt.get_builtin_function (name);
+    std::vector<gccjit::rvalue> gccjit_args (nargs);
+    for (size_t i = 0; i < nargs; ++i)
+      gccjit_args[i] = gf.get_param (i + 1);
+    gccjit::rvalue ret = gccjit_ctxt.new_call (builtin, gccjit_args);
+    gccjit::block b = gf.new_block ();
+    b.end_with_return (ret);
+  }
+
   paren_subsref_fn.add_overload (fn);
 }
 
@@ -2102,6 +2834,8 @@
   std::copy (args.begin (), args.end (), fn_args.begin () + 1);
   jit_function fn = create_internal (name, result, fn_args);
   fn.mark_can_error ();
+
+  // LLVM implementation:
   llvm::BasicBlock *block = fn.new_block ();
   builder.SetInsertPoint (block);
   llvm::Type *any_t = any->to_llvm ();
@@ -2132,6 +2866,53 @@
 
   jit_function cast_result = cast (result, any);
   fn.do_return (builder, cast_result.call (builder, ret));
+
+  // gccjit implementation:
+  {
+    gccjit::function gf = fn.gccjit_function;
+    gccjit::block b = gf.new_block ("body of register_generic");
+    b.add_comment ("TODO: register_generic");
+
+    gccjit::type array_t = gccjit_ctxt.new_array_type (any->to_gccjit (),
+                                                       args.size ());
+#if 1
+    gccjit::lvalue array = gf.new_local (array_t, "tmp_array");
+    for (size_t i = 0; i < args.size (); ++i)
+      {
+        gccjit::lvalue arg = gf.get_param (i + 1);
+        jit_function agrab = get_grab (args[i]);
+        if (agrab.valid ())
+          {
+            std::vector<gccjit::rvalue> grab_args (1, arg);
+            b.add_assignment (arg, agrab.call (gccjit_ctxt, b, grab_args));
+          }
+        jit_function acast = cast (any, args[i]);
+        std::vector<gccjit::rvalue> cast_args (1, arg);
+        b.add_assignment (array[i],
+                          acast.call (gccjit_ctxt, b, cast_args));
+      }
+#endif
+
+    gccjit::type int_t = intN (sizeof (octave_builtin::fcn) * 8)->to_gccjit ();
+    size_t fcn_int = reinterpret_cast<size_t> (builtin->function ());
+    gccjit::rvalue fcn = gccjit_ctxt.new_rvalue (int_t, (int)fcn_int);
+    gccjit::rvalue nargin = gccjit_ctxt.new_rvalue (int_t, (int)args.size ());
+    size_t result_int = reinterpret_cast<size_t> (result);
+    gccjit::rvalue res_gcc = gccjit_ctxt.new_rvalue (int_t, (int)result_int);
+    std::vector<gccjit::rvalue> call_args (4);
+    call_args[0] = fcn;
+    call_args[1] = nargin;
+    call_args[2] = array;
+    call_args[3] = res_gcc;
+    gccjit::rvalue ret = any_call.call (gccjit_ctxt, b, call_args);
+    
+    jit_function cast_result = cast (result, any);
+    std::vector<gccjit::rvalue> final_cast_args (1);
+    final_cast_args[0] = ret;
+    gccjit::rvalue final_result = cast_result.call (gccjit_ctxt, b, final_cast_args);
+    b.end_with_return (final_result);
+  }
+
   paren_subsref_fn.add_overload (fn);
 }
 
@@ -2144,6 +2925,7 @@
   if (fn.can_error ())
     ret.mark_can_error ();
 
+  // LLVM implementation:
   llvm::BasicBlock *body = ret.new_block ();
   builder.SetInsertPoint (body);
   llvm::Value *result = fn.call (builder, ret.argument (builder, 1),
@@ -2153,9 +2935,25 @@
   else
     ret.do_return (builder);
 
+  // gccjit implementation:
+  gccjit::function gf = ret.gccjit_function;
+  gccjit::block b = gf.new_block ();
+  b.add_comment ("built by mirror_binary");
+  //std::vector<gccjit::rvalue> gccjit_args (2);
+  //gccjit_args[0] = gf.get_param (1);
+  //gccjit_args[1] = gf.get_param (0);
+  if (ret.result ())
+    b.end_with_return (
+      gccjit_ctxt.new_call (fn.gccjit_function,
+                            gf.get_param (1),
+                            gf.get_param (0)));
+  else
+    b.end_with_return ();
+
   return ret;
 }
 
+#ifdef HAVE_LLVM
 llvm::Value *
 jit_typeinfo::pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx)
 {
@@ -2216,14 +3014,63 @@
   ret = complex_real (ret, real);
   return complex_imag (ret, imag);
 }
+#endif // #ifdef HAVE_LLVM
+
+#ifdef HAVE_GCCJIT
+gccjit::rvalue
+jit_typeinfo::complex_real (gccjit::rvalue cx)
+{
+  return cx[0];
+}
+
+gccjit::rvalue
+jit_typeinfo::complex_real (gccjit::block block,
+                            gccjit::lvalue cx,
+                            gccjit::rvalue real)
+{
+  block.add_assignment (cx[0], real);
+  return cx;
+}
+
+gccjit::rvalue
+jit_typeinfo::complex_imag (gccjit::rvalue cx)
+{
+  return cx[1];
+}
+
+gccjit::rvalue
+jit_typeinfo::complex_imag (gccjit::block block,
+                            gccjit::lvalue cx,
+                            gccjit::rvalue imag)
+{
+  block.add_assignment (cx[1], imag);
+  return cx;
+}
+
+gccjit::rvalue
+jit_typeinfo::complex_new (gccjit::block block,
+                           gccjit::rvalue real,
+                           gccjit::rvalue imag)
+{
+  gccjit::rvalue tmp =
+    block.get_function ().new_local (complex->to_gccjit (),
+                                     "complex_new");
+  block.add_assignment (tmp[0], real);
+  block.add_assignment (tmp[1], imag);
+  return tmp;
+}
+#endif // #ifdef HAVE_GCCJIT
 
 void
 jit_typeinfo::create_int (size_t nbits)
 {
   std::stringstream tname;
   tname << "int" << nbits;
-  ints[nbits] = new_type (tname.str (), any, llvm::Type::getIntNTy (context,
-                                                                    nbits));
+  ints[nbits] = new_type (tname.str (), any,
+                          llvm::Type::getIntNTy (context,
+                                                 nbits),
+                          gccjit_ctxt.get_int_type (nbits / 8, 1)
+                          );
 }
 
 jit_type *
diff --git a/libinterp/corefcn/jit-typeinfo.h b/libinterp/corefcn/jit-typeinfo.h
--- a/libinterp/corefcn/jit-typeinfo.h
+++ b/libinterp/corefcn/jit-typeinfo.h
@@ -25,7 +25,7 @@
 #if !defined (octave_jit_typeinfo_h)
 #define octave_jit_typeinfo_h 1
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 
 #include <map>
 #include <vector>
@@ -33,6 +33,10 @@
 #include "Range.h"
 #include "jit-util.h"
 
+#ifdef HAVE_GCCJIT
+#include "libgccjit++.h"
+#endif
+
 // Defines the type system used by jit and a singleton class, jit_typeinfo, to
 // manage the types.
 //
@@ -133,10 +137,18 @@
 jit_type
 {
 public:
+#ifdef HAVE_LLVM
   typedef llvm::Value *(*convert_fn) (llvm::IRBuilderD&, llvm::Value *);
+#endif
 
-  jit_type (const std::string& aname, jit_type *aparent, llvm::Type *allvm_type,
-            bool askip_paren, int aid);
+  jit_type (const std::string& aname, jit_type *aparent
+#ifdef HAVE_LLVM
+            , llvm::Type *allvm_type
+#endif
+#ifdef HAVE_GCCJIT
+            , gccjit::type agcc_type
+#endif
+            , bool askip_paren, int aid);
 
   // a user readable type name
   const std::string& name (void) const { return mname; }
@@ -147,11 +159,17 @@
   // An abstract base type, may be null
   jit_type *parent (void) const { return mparent; }
 
+#ifdef HAVE_LLVM
   // convert to an llvm type
   llvm::Type *to_llvm (void) const { return llvm_type; }
 
   // how this type gets passed as a function argument
   llvm::Type *to_llvm_arg (void) const;
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::type to_gccjit (void) const { return gccjit_type; }
+#endif
 
   size_t depth (void) const { return mdepth; }
 
@@ -179,6 +197,7 @@
   // 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.
+#ifdef HAVE_LLVM
   convert_fn pack (jit_convention::type cc) { return mpack[cc]; }
 
   void set_pack (jit_convention::type cc, convert_fn fn) { mpack[cc] = fn; }
@@ -195,10 +214,17 @@
 
   void set_packed_type (jit_convention::type cc, llvm::Type *ty)
   { mpacked_type[cc] = ty; }
+#endif
+
 private:
   std::string mname;
   jit_type *mparent;
+#ifdef HAVE_LLVM
   llvm::Type *llvm_type;
+#endif
+#ifdef HAVE_GCCJIT
+  gccjit::type gccjit_type;
+#endif
   int mid;
   size_t mdepth;
   bool mskip_paren;
@@ -206,12 +232,13 @@
   bool msret[jit_convention::length];
   bool mpointer_arg[jit_convention::length];
 
+#ifdef HAVE_LLVM
   convert_fn mpack[jit_convention::length];
   convert_fn munpack[jit_convention::length];
 
   llvm::Type *mpacked_type[jit_convention::length];
+#endif
 };
-
 // seperate print function to allow easy printing if type is null
 std::ostream& jit_print (std::ostream& os, jit_type *atype);
 
@@ -227,8 +254,16 @@
   // create a function in an invalid state
   jit_function ();
 
-  jit_function (llvm::Module *amodule, jit_convention::type acall_conv,
-                const llvm::Twine& aname, jit_type *aresult,
+  jit_function (
+#ifdef HAVE_LLVM
+                llvm::Module *amodule,
+#endif
+#ifdef HAVE_GCCJIT
+                gccjit::context gccjit_ctxt,
+#endif
+                jit_convention::type acall_conv,
+                std::string aname,
+                jit_type *aresult,
                 const std::vector<jit_type *>& aargs);
 
   // Use an existing function, but change the argument types. The new argument
@@ -241,6 +276,7 @@
   // erase the interal LLVM function (if it exists). Will become invalid.
   void erase (void);
 
+#ifdef HAVE_LLVM
   template <typename T>
   void add_mapping (llvm::ExecutionEngine *engine, T fn)
   {
@@ -248,9 +284,13 @@
   }
 
   bool valid (void) const { return llvm_function; }
+#else
+  bool valid (void) const;
+#endif
 
   std::string name (void) const;
 
+#ifdef HAVE_LLVM
   llvm::BasicBlock *new_block (const std::string& aname = "body",
                                llvm::BasicBlock *insert_before = 0);
 
@@ -289,6 +329,17 @@
                   bool verify = true);
 
   llvm::Function *to_llvm (void) const { return llvm_function; }
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::rvalue call (gccjit::context ctxt,
+                       gccjit::block block,
+                       const std::vector<jit_value *>& in_args) const;
+  gccjit::rvalue call (gccjit::context ctxt,
+                       gccjit::block block,
+                       std::vector<gccjit::rvalue>& in_args) const;
+  gccjit::lvalue argument (size_t idx) const;
+#endif
 
   // If true, then the return value is passed as a pointer in the first argument
   bool sret (void) const { return mresult && mresult->sret (call_conv); }
@@ -307,10 +358,17 @@
 
   const std::vector<jit_type *>& arguments (void) const { return args; }
 private:
+#ifdef HAVE_LLVM
   void do_add_mapping (llvm::ExecutionEngine *engine, void *fn);
 
   llvm::Module *module;
   llvm::Function *llvm_function;
+#endif
+#ifdef HAVE_GCCJIT
+public:
+  gccjit::function gccjit_function;
+private:
+#endif
   jit_type *mresult;
   std::vector<jit_type *> args;
   jit_convention::type call_conv;
@@ -389,14 +447,19 @@
 jit_index_operation : public jit_operation
 {
 public:
-  jit_index_operation (void) : module (0), engine (0) { }
+  jit_index_operation (void) {} //: module (0), engine (0) { }
 
-  void initialize (llvm::Module *amodule, llvm::ExecutionEngine *aengine)
+#ifdef HAVE_LLVM
+  void initialize (llvm::Module *amodule, llvm::ExecutionEngine *aengine,
+                   gccjit::context agccjit_ctxt)
   {
     module = amodule;
     engine = aengine;
+    gccjit_ctxt = agccjit_ctxt;
     do_initialize ();
   }
+#endif
+
 protected:
   virtual jit_function *generate (const signature_vec& types) const;
 
@@ -406,12 +469,22 @@
 
   // helper functions
   // [start_idx, end_idx).
+#ifdef HAVE_LLVM
   llvm::Value *create_arg_array (llvm::IRBuilderD& builder,
                                  const jit_function &fn, size_t start_idx,
                                  size_t end_idx) const;
 
   llvm::Module *module;
   llvm::ExecutionEngine *engine;
+#endif
+#ifdef HAVE_GCCJIT
+  gccjit::rvalue create_arg_array (const jit_function &fn,
+                                   gccjit::block block,
+                                   size_t start_idx,
+                                   size_t end_idx) const;
+
+  gccjit::context gccjit_ctxt;
+#endif
 };
 
 class
@@ -442,7 +515,11 @@
 jit_typeinfo
 {
 public:
-  static void initialize (llvm::Module *m, llvm::ExecutionEngine *e);
+  static void initialize (
+#ifdef HAVE_LLVM                          
+                          llvm::Module *m, llvm::ExecutionEngine *e
+#endif
+                          );
 
   static jit_type *join (jit_type *lhs, jit_type *rhs)
   {
@@ -454,9 +531,14 @@
   static jit_type *get_matrix (void) { return instance->matrix; }
 
   static jit_type *get_scalar (void) { return instance->scalar; }
-
+#ifdef HAVE_LLVM
   static llvm::Type *get_scalar_llvm (void)
   { return instance->scalar->to_llvm (); }
+#endif
+#ifdef HAVE_GCCJIT
+  static gccjit::type get_scalar_gccjit (void)
+  { return instance->scalar->to_gccjit (); }
+#endif
 
   static jit_type *get_scalar_ptr (void) { return instance->scalar_ptr; }
 
@@ -470,8 +552,10 @@
 
   static jit_type *get_index (void) { return instance->index; }
 
+#ifdef HAVE_LLVM
   static llvm::Type *get_index_llvm (void)
   { return instance->index->to_llvm (); }
+#endif
 
   static jit_type *get_complex (void) { return instance->complex; }
 
@@ -563,6 +647,7 @@
     return instance->do_cast (to, from);
   }
 
+#ifdef HAVE_LLVM
   static llvm::Value *insert_error_check (llvm::IRBuilderD& bld)
   {
     return instance->do_insert_error_check (bld);
@@ -572,6 +657,18 @@
   {
     return instance->do_insert_interrupt_check (bld);
   }
+#endif
+#ifdef HAVE_GCCJIT
+  static gccjit::rvalue insert_error_check (gccjit::function func)
+  {
+    return instance->do_insert_error_check (func);
+  }
+
+  static gccjit::rvalue insert_interrupt_check (gccjit::function func)
+  {
+    return instance->do_insert_interrupt_check (func);
+  }
+#endif
 
   static const jit_operation& end (void)
   {
@@ -589,12 +686,25 @@
     return instance->create_undef_fn;
   }
 
+#ifdef HAVE_LLVM
   static llvm::Value *create_complex (llvm::Value *real, llvm::Value *imag)
   {
     return instance->complex_new (real, imag);
   }
+#endif
+
+#ifdef HAVE_GCCJIT
+  static gccjit::context create_gccjit_child_context ()
+  {
+    return instance->gccjit_ctxt.new_child_context ();
+  }
+#endif
+
+
 private:
+#ifdef HAVE_LLVM
   jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e);
+#endif
 
   // FIXME: Do these methods really need to be in jit_typeinfo?
   jit_type *do_join (jit_type *lhs, jit_type *rhs)
@@ -668,35 +778,58 @@
   const jit_function& do_end (jit_value *value, jit_value *index,
                               jit_value *count);
 
-  jit_type *new_type (const std::string& name, jit_type *parent,
-                      llvm::Type *llvm_type, bool skip_paren = false);
-
+  jit_type *new_type (const std::string& name, jit_type *parent
+#ifdef HAVE_LLVM
+                      , llvm::Type *llvm_type
+#endif
+#ifdef HAVE_GCCJIT
+                      , gccjit::type gccjit_type
+#endif
+                      , bool skip_paren = false);
 
   void add_print (jit_type *ty, void *fptr);
 
-  void add_binary_op (jit_type *ty, int op, int llvm_op);
+  void add_binary_op (jit_type *ty, int op,
+                      int llvm_op,
+                      enum gcc_jit_binary_op gccjit_op);
 
-  void add_binary_icmp (jit_type *ty, int op, int llvm_op);
+  void add_binary_icmp (jit_type *ty, int op,
+                        int llvm_op,
+                        enum gcc_jit_comparison gccjit_op);
 
-  void add_binary_fcmp (jit_type *ty, int op, int llvm_op);
+  void add_binary_fcmp (jit_type *ty, int op,
+                        int llvm_op,
+                        enum gcc_jit_comparison gccjit_op);
 
   // create a function with an external calling convention
   // forces the function pointer to be specified
   template <typename T>
-  jit_function create_external (llvm::ExecutionEngine *ee, T fn,
-                                const llvm::Twine& name, jit_type *ret,
+    jit_function create_external (
+#ifdef HAVE_LLVM
+  llvm::ExecutionEngine *ee,
+#endif
+                                T fn,
+                                std::string name, jit_type *ret,
                                 const std::vector<jit_type *>& args
                                 = std::vector<jit_type *> ())
   {
     jit_function retval = create_function (jit_convention::external, name, ret,
                                            args);
+#ifdef HAVE_LLVM
     retval.add_mapping (ee, fn);
+#endif
     return retval;
   }
 
+#ifdef HAVE_LLVM
 #define JIT_PARAM_ARGS llvm::ExecutionEngine *ee, T fn,     \
-    const llvm::Twine& name, jit_type *ret,
+    std::string name, jit_type *ret,
 #define JIT_PARAMS ee, fn, name, ret,
+#else
+#define JIT_PARAM_ARGS T fn,     \
+    std::string name, jit_type *ret,
+#define JIT_PARAMS fn, name, ret,
+#endif
 #define CREATE_FUNCTION(N) JIT_EXPAND(template <typename T> jit_function, \
                                       create_external,                  \
                                       jit_type *, /* empty */, N)
@@ -712,19 +845,19 @@
 
   // use create_external or create_internal directly
   jit_function create_function (jit_convention::type cc,
-                                const llvm::Twine& name, jit_type *ret,
+                                std::string name, jit_type *ret,
                                 const std::vector<jit_type *>& args
                                 = std::vector<jit_type *> ());
 
   // create an internal calling convention (a function defined in llvm)
-  jit_function create_internal (const llvm::Twine& name, jit_type *ret,
+  jit_function create_internal (std::string name, jit_type *ret,
                                 const std::vector<jit_type *>& args
                                 = std::vector<jit_type *> ())
   {
     return create_function (jit_convention::internal, name, ret, args);
   }
 
-#define JIT_PARAM_ARGS const llvm::Twine& name, jit_type *ret,
+#define JIT_PARAM_ARGS std::string name, jit_type *ret,
 #define JIT_PARAMS name, ret,
 #define CREATE_FUNCTION(N) JIT_EXPAND(jit_function, create_internal,    \
                                       jit_type *, /* empty */, N)
@@ -740,9 +873,17 @@
 
   jit_function create_identity (jit_type *type);
 
+#ifdef HAVE_LLVM
   llvm::Value *do_insert_error_check (llvm::IRBuilderD& bld);
 
   llvm::Value *do_insert_interrupt_check (llvm::IRBuilderD& bld);
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::rvalue do_insert_error_check (gccjit::function func);
+
+  gccjit::rvalue do_insert_interrupt_check (gccjit::function func);
+#endif
 
   void add_builtin (const std::string& name);
 
@@ -770,6 +911,7 @@
 
   jit_function mirror_binary (const jit_function& fn);
 
+#ifdef HAVE_LLVM
   llvm::Function *wrap_complex (llvm::Function *wrap);
 
   static llvm::Value *pack_complex (llvm::IRBuilderD& bld,
@@ -787,6 +929,25 @@
   llvm::Value *complex_imag (llvm::Value *cx, llvm::Value *imag);
 
   llvm::Value *complex_new (llvm::Value *real, llvm::Value *imag);
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::rvalue complex_real (gccjit::rvalue cx);
+
+  gccjit::rvalue complex_real (gccjit::block block,
+                               gccjit::lvalue cx,
+                               gccjit::rvalue real);
+
+  gccjit::rvalue complex_imag (gccjit::rvalue cx);
+
+  gccjit::rvalue complex_imag (gccjit::block block,
+                               gccjit::lvalue cx,
+                               gccjit::rvalue imag);
+
+  gccjit::rvalue complex_new (gccjit::block block,
+                              gccjit::rvalue real,
+                              gccjit::rvalue imag);
+#endif
 
   void create_int (size_t nbits);
 
@@ -794,22 +955,45 @@
 
   static jit_typeinfo *instance;
 
+#ifdef HAVE_LLVM
   llvm::Module *module;
   llvm::ExecutionEngine *engine;
+#endif
   int next_id;
 
+#ifdef HAVE_LLVM
   llvm::GlobalVariable *lerror_state;
   llvm::GlobalVariable *loctave_interrupt_state;
 
   llvm::Type *sig_atomic_type;
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::rvalue error_state_gccjit;
+  gccjit::rvalue octave_interrupt_state_gccjit;
+  gccjit::type sig_atomic_type_gccjit;
+#endif
 
   std::vector<jit_type*> id_to_type;
   jit_type *any;
   jit_type *matrix;
+#ifdef HAVE_GCCJIT  
+  gccjit::field field_ref_count;
+  gccjit::field field_slice_data;
+  gccjit::field field_slice_len;
+  gccjit::field field_dimensions;
+  gccjit::field field_array;
+#endif
   jit_type *scalar;
   jit_type *scalar_ptr; // a fake type for interfacing with C++
   jit_type *any_ptr; // a fake type for interfacing with C++
   jit_type *range;
+#ifdef HAVE_GCCJIT  
+  gccjit::field field_rng_base;
+  gccjit::field field_rng_limit;
+  gccjit::field field_rng_inc;
+  gccjit::field field_rng_nelem;
+#endif
   jit_type *string;
   jit_type *boolean;
   jit_type *index;
@@ -818,7 +1002,9 @@
   std::map<size_t, jit_type *> ints;
   std::map<std::string, jit_type *> builtins;
 
+#ifdef HAVE_LLVM
   llvm::StructType *complex_ret;
+#endif
 
   std::vector<jit_operation> binary_ops;
   std::vector<jit_operation> unary_ops;
@@ -845,8 +1031,14 @@
   // type id -> identity function
   std::vector<jit_function> identities;
 
+#ifdef HAVE_LLVM
   llvm::IRBuilderD& builder;
+#endif
+
+#ifdef HAVE_GCCJIT
+  gccjit::context gccjit_ctxt;
+#endif
 };
 
+#endif /* ifdef HAVE_JIT */
 #endif
-#endif
diff --git a/libinterp/corefcn/jit-util.h b/libinterp/corefcn/jit-util.h
--- a/libinterp/corefcn/jit-util.h
+++ b/libinterp/corefcn/jit-util.h
@@ -27,14 +27,14 @@
 #if !defined (octave_jit_util_h)
 #define octave_jit_util_h 1
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 
 #include <stdexcept>
 
 #if defined(HAVE_LLVM_IR_DATALAYOUT_H) || defined(HAVE_LLVM_DATALAYOUT_H)
 #define HAVE_LLVM_DATALAYOUT
 #endif
-
+#if HAVE_LLVM
 // 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
@@ -66,6 +66,7 @@
 typedef IRBuilder<true, ConstantFolder, IRBuilderDefaultInserter<true> >
 IRBuilderD;
 }
+#endif /* if HAVE_LLVM */
 
 class octave_base_value;
 class octave_builtin;
@@ -88,7 +89,9 @@
 };
 
 // llvm doesn't provide this, and it's really useful for debugging
+#if HAVE_LLVM
 std::ostream& operator<< (std::ostream& os, const llvm::Value& v);
+#endif
 
 template <typename HOLDER_T, typename SUB_T>
 class jit_internal_node;
@@ -205,5 +208,5 @@
     return fname (JIT_PARAMS the_args);                                 \
   }
 
+#endif /* ifdef HAVE_JIT */
 #endif
-#endif
diff --git a/libinterp/corefcn/pt-jit.cc b/libinterp/corefcn/pt-jit.cc
--- a/libinterp/corefcn/pt-jit.cc
+++ b/libinterp/corefcn/pt-jit.cc
@@ -38,16 +38,17 @@
 #include "symtab.h"
 #include "variables.h"
 
+#ifdef HAVE_JIT
+
+static bool Vdebug_jit = false;
+
+static bool Vjit_enable = false;
+
+static int Vjit_startcnt = 1000;
+
+static int Vjit_failure_count = 0;
+
 #ifdef HAVE_LLVM
-
-static bool Vdebug_jit = false;
-
-static bool Vjit_enable = false;
-
-static int Vjit_startcnt = 1000;
-
-static int Vjit_failure_count = 0;
-
 #include <llvm/Analysis/CallGraph.h>
 #include <llvm/Analysis/Passes.h>
 #include <llvm/Analysis/Verifier.h>
@@ -90,6 +91,8 @@
 
 static llvm::LLVMContext& context = llvm::getGlobalContext ();
 
+#endif /* ifdef HAVE_LLVM */
+
 // -------------------- jit_break_exception --------------------
 
 // jit_break is thrown whenever a branch we are converting has only breaks or
@@ -1281,7 +1284,564 @@
     }
 }
 
+// -------------------- jit_convert_gcc --------------------
+
+jit_convert_gcc::jit_convert_gcc ()
+  : m_blocks (NULL),
+    m_constants (NULL),
+    m_ctxt (jit_typeinfo::create_gccjit_child_context ()),
+    m_func (),
+    m_extracted_params (),
+    m_block_map (),
+    m_locals_for_insns (),
+    m_block_stack (),
+    m_log_visits (false)
+{
+  // FIXME: error-handling
+
+  m_ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+                         3);
+
+  // Diagnostics, debugging etc:
+  if (1)
+    {
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO,
+                              1);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+                              0);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+                              1);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+                              1);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+                              0);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+                              1);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+                              0);
+      m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+                              1);
+    }
+}
+
+jit_convert_gcc::~jit_convert_gcc ()
+{
+  m_ctxt.release ();
+}
+
+gcc_jit_result *
+jit_convert_gcc::convert_loop (const jit_block_list& blocks,
+                               const std::list<jit_value *>& constants)
+{
+  converting_function = false;
+
+  m_blocks = &blocks;
+  m_constants = &constants;
+
+  jit_type *any = jit_typeinfo::get_any ();
+  // argument is an array of octave_base_value*, or octave_base_value**
+  gccjit::type arg_type = any->to_gccjit (); // this is octave_base_value*
+  arg_type = arg_type.get_pointer ();
+
+  // for now just init arguments from entry, later we will have to do something
+  // more interesting
+  jit_block *entry_block = m_blocks->front ();
+  for (jit_block::iterator iter = entry_block->begin ();
+       iter != entry_block->end (); ++iter)
+    if (jit_extract_argument *extract
+        = dynamic_cast<jit_extract_argument *> (*iter))
+      {
+        m_argument_index[extract->name ()] = m_argument_vec.size ();
+        m_argument_vec.push_back (std::make_pair (extract->name (), true));
+      }
+
+  /* We have a single param, confusingly named "params" (an array).  */
+  params = m_ctxt.new_param (arg_type, "params");
+  
+  std::vector<gccjit::param> params_of_fn (1, params);
+
+  m_func = m_ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                                m_ctxt.get_type (GCC_JIT_TYPE_VOID),
+                                "loop",
+                                params_of_fn,
+                                0);
+
+  gccjit::block initial_block = m_func.new_block ("initial");
+
+  /* Create gccjit::blocks for each jit_block, and for each edge.
+
+     We're converting from an SSA representation back to a non-SSA
+     representation, hence we need to convert phi nodes into regular
+     assignments.  To do this, introduce a gccjit::block for each edge, to
+     handle the phis along each edges.  Jumps to blocks in the JIT-IR
+     will become jumps to edge-handling gccjit::blocks in our CFG; each
+     such "edge" block will end with a jump to the "real" gccjit::block.  */
+  std::list<jit_block *>::const_iterator block_iter;
+  for (block_iter = m_blocks->begin ();
+       block_iter != m_blocks->end ();
+       ++block_iter)
+    {
+      jit_block *jblock = *block_iter;
+      
+      // Find predecessor blocks
+      for (jit_use *use = jblock->first_use (); use; use = use->next ())
+        {
+          jit_block *pred = use->user_parent ();
+
+          /* Create edge-handling gccjit::block.  */
+          m_blocks_for_edges[std::make_pair(pred, jblock)] =
+            m_func.new_block (std::string ("edge_from_")
+                              + pred->name_and_id ()
+                              + std::string ("_to_")
+                              + jblock->name_and_id ());
+        }
+
+      /* The "real" gccjit::block.  */
+      m_block_map[jblock] =
+        m_func.new_block (jblock->name_and_id ());
+    }
+
+  /* It's an SSA representation, so we have another pass here that
+     creates a local for every statement.  */
+  for (block_iter = m_blocks->begin ();
+       block_iter != m_blocks->end ();
+       ++block_iter)
+    for (jit_block::iterator insn_iter = (*block_iter)->begin ();
+         insn_iter != (*block_iter)->end ();
+         ++insn_iter)
+      {
+        jit_instruction *insn = *insn_iter;
+
+        /* Some insns have NULL type e.g. conditional branches; it only
+           makes sense to create a local for those with actual types.  */
+        if (insn->type ())
+          {
+            std::stringstream ss;
+            // FIXME: perhaps make these identifiers look less weird?
+            // that said, the short_print vfunc conveys more information
+            ss << "(";
+            insn->short_print (ss);
+            ss << ")";
+
+            m_locals_for_insns[insn] =
+              m_func.new_local (insn->type_gccjit (),
+                                ss.str ().c_str ());
+
+            insn->stash_rvalue (m_locals_for_insns[insn]);
+          }
+      }
+
+  // constants aren't in the IR, we visit those first
+  for (std::list<jit_value *>::const_iterator iter = m_constants->begin ();
+       iter != m_constants->end (); ++iter)
+    if (! isa<jit_instruction> (*iter))
+      visit (*iter);
+
+  /* Prelude: extract params from the "params" array.  */
+  if (m_with_comments)
+    initial_block.add_comment ("prelude");
+  for (int i = 0; i < m_argument_vec.size (); ++i)
+    {
+      gccjit::lvalue extracted_param =
+        m_func.new_local (any->to_gccjit (),
+                          "extracted_param_" + m_argument_vec[i].first);
+      m_extracted_params.push_back (extracted_param);
+      initial_block.add_assignment (
+        extracted_param,
+        m_ctxt.new_array_access (
+          params,
+          m_ctxt.new_rvalue (m_ctxt.get_type (GCC_JIT_TYPE_INT),
+                             i)));
+    }
+  initial_block.end_with_jump (m_block_map[*m_blocks->begin ()]);
+
+  // convert all instructions
+  for (block_iter = m_blocks->begin (); block_iter != m_blocks->end (); ++block_iter)
+    visit (**block_iter);
+
+  m_ctxt.dump_to_file ("/tmp/loop-dump.c", true);
+
+  m_func.dump_to_dot ("/tmp/loop.dot");
+
+  return m_ctxt.compile ();
+}
+
+#if 0
+gccjit::lvalue
+jit_convert_gcc::as_lvalue (jit_value *jval)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::as_lvalue (jit_value *jval): " << *jval << "\n";
+
+  if (!jval->has_lvalue ())
+    {
+      gccjit::lvalue local =
+        m_func.new_local (/* FIXME: */
+                          m_ctxt.get_type (GCC_JIT_TYPE_INT),
+                          jval->print_string ().c_str ());
+      jval->stash_lvalue (local);
+    }
+
+  return jval->as_lvalue ();
+}
+#endif
+
+gccjit::rvalue
+jit_convert_gcc::as_rvalue (jit_value *jval)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::as_rvalue (jit_value *jval): " << *jval << "\n";
+  //std::map<jit_value *, gcc_jit_rvalue *> m_rvalues;
+
+  if (jit_instruction *insn = dynamic_cast<jit_instruction *> (jval))
+    {
+      return m_locals_for_insns[insn];
+    }
+
+  //  return gcc_jit_lvalue_as_rvalue (as_lvalue (jval));
+  return jval->as_rvalue ();
+}
+
+void
+jit_convert_gcc::add_assignment_for_insn (jit_instruction &insn,
+                                          gccjit::rvalue val)
+{
+  //insn.stash_rvalue (val);
+  if (insn.type ())
+    get_current_block ().add_assignment (m_locals_for_insns[&insn],
+                                         val);
+  //TODO: use location of insn
+}
+
+gccjit::block
+jit_convert_gcc::get_block_for_edge (jit_block *src, jit_block *dest)
+{
+  return m_blocks_for_edges[std::make_pair (src, dest)];
+}
+
+gccjit::block
+jit_convert_gcc::get_current_block ()
+{
+  assert (!m_block_stack.empty ());
+  return m_block_stack.top ();
+}
+
+void
+jit_convert_gcc::push_block (gccjit::block block)
+{
+  m_block_stack.push (block);
+}
+
+void
+jit_convert_gcc::pop_block ()
+{
+  m_block_stack.pop ();
+}
+
+  //std::vector<gccjit::block> m_current_block_stack;
+
+
+void
+jit_convert_gcc::visit (jit_const_string& cs)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_const_string& cs): " << cs << "\n";
+  gccjit::rvalue rvalue = m_ctxt.new_rvalue (cs.value ());
+  cs.stash_rvalue (rvalue);
+}
+
+void
+jit_convert_gcc::visit (jit_const_bool& cb)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_const_bool& cb): " << cb << "\n";
+  gccjit::rvalue rvalue = m_ctxt.new_rvalue (cb.type_gccjit (),
+                                             cb.value ());
+  cb.stash_rvalue (rvalue);
+}
+
+void
+jit_convert_gcc::visit (jit_const_scalar& cs)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_const_scalar& cs): " << cs << "\n";
+  gccjit::rvalue rvalue = m_ctxt.new_rvalue (cs.type_gccjit (),
+                                             cs.value ());
+  cs.stash_rvalue (rvalue);
+}
+
+void
+jit_convert_gcc::visit (jit_const_complex& cc)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_const_complex& cc): " << cc << "\n";
+#if 0
+  gccjit::rvalue rvalue = m_ctxt.new_rvalue (cc.type_gccjit (),
+                                             cc.value ());
+  cc.stash_rvalue (rvalue);
+#else
+  throw jit_fail_exception ("TODO");
+#endif
+}
+
+void jit_convert_gcc::visit (jit_const_index& ci)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_const_index& ci): " << ci << "\n";
+  gccjit::rvalue rvalue = m_ctxt.new_rvalue (ci.type_gccjit (),
+                                             ci.value ());
+  ci.stash_rvalue (rvalue);
+}
+
+void
+jit_convert_gcc::visit (jit_const_range& cr)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_const_range& cr): " << cr << "\n";
+#if 0
+  gccjit::rvalue rvalue = m_ctxt.new_rvalue (cr.type_gccjit (),
+                                             cr.value ());
+  cr.stash_rvalue (rvalue);
+#else
+  throw jit_fail_exception ("TODO");
+#endif
+}
+
+void
+jit_convert_gcc::visit (jit_block& b)
+{
+  /* First, handle the phi nodes by populating the edge-handling blocks
+     with assignments that set up the phi nodes's lvalues based on the incoming
+     edge, then jumping to the "real" block for this block.  */
+  for (jit_block::iterator insn_iter = b.begin ();
+       insn_iter != b.end ();
+       ++insn_iter)
+    if (jit_phi *phi = dynamic_cast<jit_phi *> (*insn_iter))
+      {
+        for (size_t i = 0; i < phi->argument_count (); ++i)
+          {
+            jit_block *pred = phi->incomming (i);
+            push_block (m_blocks_for_edges[std::make_pair(pred, &b)]);
+            if (m_with_comments)
+              {
+                std::ostringstream os;
+                os << "incoming edge " << i << " for: ";
+                phi->print (os);
+                get_current_block ().add_comment (os.str ());
+              }
+            get_current_block ().add_assignment (
+              m_locals_for_insns[phi],
+              m_locals_for_insns[static_cast <jit_instruction *> (phi->argument (i))]);
+            pop_block ();
+          }
+      }
+
+  /* Terminate the blocks for edges leading to this block.  */
+  jit_use *use;
+  for (use = b.first_use (); use; use = use->next ())
+    {
+      jit_block *pred = use->user_parent ();
+      gccjit::block block_for_edge =
+        m_blocks_for_edges[std::make_pair(pred, &b)];
+      block_for_edge.end_with_jump (m_block_map[&b]);
+    }
+  
+  /* Now generate a block for all of the non-phi instructions.  */
+  push_block (m_block_map[&b]);
+  for (jit_block::iterator insn_iter = b.begin ();
+       insn_iter != b.end ();
+       ++insn_iter)
+    {
+      // We've handled phi nodes above; skip them:
+      if (dynamic_cast<jit_phi *> (*insn_iter))
+        continue;
+
+      if (m_with_comments)
+        get_current_block ().add_comment (std::string ("jit_instruction:   ")
+                                          + (*insn_iter)->print_string ());
+      visit (*insn_iter);
+    }
+  pop_block ();
+}
+
+void
+jit_convert_gcc::visit (jit_branch& b)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_branch& b): " << b << "\n";
+
+  jit_block *this_block = b.parent (); 
+  jit_block *next = b.successor ();
+
+  get_current_block ().end_with_jump (get_block_for_edge (this_block, next));
+}
+
+void
+jit_convert_gcc::visit (jit_cond_branch& cb)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_cond_branch& cb): " << cb << "\n";
+
+  gccjit::rvalue boolval = as_rvalue (cb.cond ());
+
+  jit_block *this_block = cb.parent ();
+  get_current_block ().end_with_conditional (
+    boolval,
+    get_block_for_edge (this_block, cb.successor (0)),
+    get_block_for_edge (this_block, cb.successor (1)));
+}
+
+void
+jit_convert_gcc::visit (jit_call& call)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_call& call): " << call << "\n";
+
+  const jit_function& ol = call.overload ();
+
+  std::vector<jit_value *> args (call.arguments ().size ());
+  for (size_t i = 0; i < args.size (); ++i)
+    args[i] = call.argument (i);
+
+  gccjit::rvalue ret = ol.call (m_ctxt, get_current_block (), args);
+  add_assignment_for_insn (call, ret);
+}
+
+void
+jit_convert_gcc::visit (jit_extract_argument& extract)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_extract_argument& extract): " << extract << "\n";
+
+  const std::string& argname = extract.name ();
+
+  // Get the stored (octave_base_value *)
+  gccjit::lvalue param = m_extracted_params[m_argument_index[argname]];
+
+  // Convert it to a more specialized type:
+  const jit_function& ol = extract.overload ();
+  std::vector<gccjit::rvalue> args (1, param);
+  gccjit::rvalue extracted = ol.call (m_ctxt, get_current_block (), args);
+  add_assignment_for_insn (extract,
+                           extracted);
+}
+
+void
+jit_convert_gcc::visit (jit_store_argument& store)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_store_argument& store): " << store << "\n";
+
+  const jit_function& ol = store.overload ();
+
+  std::vector<jit_value *> args (1);
+  args[0] = store.result ();
+
+  gccjit::rvalue ret = ol.call (m_ctxt, get_current_block (), args);
+  int index = m_argument_index[store.name ()];
+  get_current_block ().add_assignment (
+    // "params[index] = ..."
+    m_ctxt.new_array_access (
+      params,
+      m_ctxt.new_rvalue (m_ctxt.get_type (GCC_JIT_TYPE_INT),
+                         index)),
+    // "... = ret;"
+    ret);
+}
+
+void
+jit_convert_gcc::visit (jit_return& ret)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_return& ret): " << ret << "\n";
+  jit_value *res = ret.result ();
+
+  if (converting_function)
+    throw jit_fail_exception ("TODO");
+  else
+    {
+      if (res)
+        get_current_block ().end_with_return (res->as_rvalue ());
+      else
+        get_current_block ().end_with_return ();
+    }
+}
+
+void
+jit_convert_gcc::visit (jit_phi& phi)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_phi& phi): " << phi << "\n";
+  throw jit_fail_exception ("TODO");
+}
+
+void
+jit_convert_gcc::visit (jit_variable& var)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_variable&): " << var << "\n";
+  throw jit_fail_exception ("TODO");
+}
+
+void
+jit_convert_gcc::visit (jit_error_check& check)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_error_check& check): " << check << "\n";
+
+  gccjit::rvalue cond;
+
+  switch (check.check_variable ())
+    {
+    case jit_error_check::var_error_state:
+      cond = jit_typeinfo::insert_error_check (m_func);
+      break;
+    case jit_error_check::var_interrupt:
+      cond = jit_typeinfo::insert_interrupt_check (m_func);
+      break;
+    default:
+      panic_impossible ();
+    }
+
+  jit_block *this_block = check.parent ();
+  get_current_block ().end_with_conditional (
+    cond,
+    get_block_for_edge (this_block, check.successor (0)),
+    get_block_for_edge (this_block, check.successor (1)));
+}
+
+void
+jit_convert_gcc::visit (jit_assign& assign)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_assign& assign): " << assign << "\n";
+
+  jit_value *jsrc = assign.src ();
+
+  add_assignment_for_insn (assign,
+                           as_rvalue (jsrc));
+}
+
+void
+jit_convert_gcc::visit (jit_argument& arg)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_argument&): " << arg << "\n";
+  throw jit_fail_exception ("TODO");
+}
+
+void
+jit_convert_gcc::visit (jit_magic_end& me)
+{
+  if (m_log_visits)
+    std::cerr << "jit_convert_gcc::visit (jit_magic_end& me): " << me << "\n";
+  throw jit_fail_exception ("TODO");
+}
+
 // -------------------- jit_convert_llvm --------------------
+
+#ifdef HAVE_LLVM
+
 llvm::Function *
 jit_convert_llvm::convert_loop (llvm::Module *module,
                                 const jit_block_list& blocks,
@@ -1347,7 +1907,9 @@
   jit_return *ret = dynamic_cast<jit_return *> (final_block->back ());
   assert (ret);
 
-  creating = jit_function (module, jit_convention::internal,
+  creating = jit_function (module,
+                           gccjit::context (), // FIXME?
+                           jit_convention::internal,
                            "foobar", ret->result_type (), args);
   function = creating.to_llvm ();
 
@@ -1635,6 +2197,8 @@
   me.stash_llvm (ret);
 }
 
+#endif /* ifdef HAVE_LLVM */
+
 // -------------------- jit_infer --------------------
 jit_infer::jit_infer (jit_factory& afactory, jit_block_list& ablocks,
                       const variable_map& avmap)
@@ -2038,6 +2602,7 @@
 bool
 tree_jit::initialize (void)
 {
+#ifdef HAVE_LLVM
   if (engine)
     return true;
 
@@ -2070,8 +2635,13 @@
   pass_manager->add (llvm::createGVNPass ());
   pass_manager->add (llvm::createCFGSimplificationPass ());
   pass_manager->doInitialization ();
-
-  jit_typeinfo::initialize (module, engine);
+#endif /* ifdef HAVE_LLVM */
+
+  jit_typeinfo::initialize (
+#ifdef HAVE_LLVM
+                            module, engine
+#endif
+);
 
   return true;
 }
@@ -2158,7 +2728,7 @@
   return 0;
 }
 
-
+#ifdef HAVE_LLVM
 void
 tree_jit::optimize (llvm::Function *fn)
 {
@@ -2176,8 +2746,10 @@
       llvm::WriteBitcodeToFile (module, fout);
     }
 }
+#endif /* ifdef HAVE_LLVM */
 
 // -------------------- jit_function_info --------------------
+#ifdef HAVE_JIT
 jit_function_info::jit_function_info (tree_jit& tjit,
                                       octave_user_function& fcn,
                                       const octave_value_list& ov_args)
@@ -2193,6 +2765,21 @@
   try
     {
       jit_convert conv (fcn, argument_types);
+
+      if (Vdebug_jit)
+        {
+          jit_block_list& blocks = conv.get_blocks ();
+          blocks.label ();
+          std::cout << "-------------------- Compiling function ";
+          std::cout << "--------------------\n";
+
+          tree_print_code tpc (std::cout);
+          tpc.visit_octave_user_function_header (fcn);
+          tpc.visit_statement_list (*fcn.body ());
+          tpc.visit_octave_user_function_trailer (fcn);
+          blocks.print (std::cout, "octave jit ir");
+        }
+
       jit_infer infer (conv.get_factory (), conv.get_blocks (),
                        conv.get_variable_map ());
       infer.infer ();
@@ -2217,7 +2804,6 @@
       raw_fn = to_llvm.convert_function (module, infer.get_blocks (),
                                          factory.constants (), fcn,
                                          argument_types);
-
       if (Vdebug_jit)
         {
           std::cout << "-------------------- raw function ";
@@ -2229,7 +2815,9 @@
       std::string wrapper_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 (module, jit_convention::internal, wrapper_name,
+      wrapper = jit_function (module,
+                              gccjit::context (), // FIXME
+                              jit_convention::internal, wrapper_name,
                               any_t, wrapper_args);
 
       llvm::BasicBlock *wrapper_body = wrapper.new_block ();
@@ -2294,6 +2882,7 @@
       raw_fn.erase ();
     }
 }
+#endif /* ifdef HAVE_JIT */
 
 bool
 jit_function_info::execute (const octave_value_list& ov_args,
@@ -2339,14 +2928,17 @@
 }
 
 // -------------------- jit_info --------------------
+#ifdef HAVE_LLVM
 jit_info::jit_info (tree_jit& tjit, tree& tee)
-  : engine (tjit.get_engine ()), function (0), llvm_function (0)
+  : engine (tjit.get_engine ()), function (0), llvm_function (0),
+    gccjit_result (NULL)
 {
   compile (tjit, tee);
 }
 
 jit_info::jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds)
-  : engine (tjit.get_engine ()), function (0), llvm_function (0)
+  : engine (tjit.get_engine ()), function (0), llvm_function (0),
+    gccjit_result (NULL)
 {
   compile (tjit, tee, jit_typeinfo::type_of (for_bounds));
 }
@@ -2355,7 +2947,10 @@
 {
   if (llvm_function)
     llvm_function->eraseFromParent ();
+  if (gccjit_result)
+    gcc_jit_result_release (gccjit_result);
 }
+#endif
 
 bool
 jit_info::execute (const vmap& extra_vars) const
@@ -2411,12 +3006,23 @@
   return true;
 }
 
+#ifdef HAVE_LLVM
 void
 jit_info::compile (tree_jit& tjit, tree& tee, jit_type *for_bounds)
 {
   try
     {
       jit_convert conv (tee, for_bounds);
+
+      if (Vdebug_jit)
+        {
+          jit_block_list& blocks = conv.get_blocks ();
+          blocks.label ();
+          std::cout << "-------------------- Compiling tree --------------------\n";
+          std::cout << tee.str_print_code () << std::endl;
+          blocks.print (std::cout, "octave jit ir");
+        }
+
       jit_infer infer (conv.get_factory (), conv.get_blocks (),
                        conv.get_variable_map ());
 
@@ -2432,6 +3038,11 @@
         }
 
       jit_factory& factory = conv.get_factory ();
+
+      jit_convert_gcc to_gcc;
+      gccjit_result = to_gcc.convert_loop (infer.get_blocks (),
+                                           factory.constants ());
+
       jit_convert_llvm to_llvm;
       llvm_function = to_llvm.convert_loop (tjit.get_module (),
                                             infer.get_blocks (),
@@ -2446,12 +3057,18 @@
           if (e.known ())
             std::cout << "jit fail: " << e.what () << std::endl;
         }
-
-      Vjit_failure_count++;
-
     }
-
-  if (llvm_function)
+  if (gccjit_result)
+    {
+      if (Vdebug_jit)
+        {
+          std::cout << "-------------------- gccjit --------------------";
+          void *void_fn = gcc_jit_result_get_code (gccjit_result, "loop");
+          function = reinterpret_cast<jited_function> (void_fn);
+        }      
+      printf ("using gccjit function\n");
+    }
+  else if (llvm_function)
     {
       if (Vdebug_jit)
         {
@@ -2473,6 +3090,7 @@
       function = reinterpret_cast<jited_function> (void_fn);
     }
 }
+#endif
 
 octave_value
 jit_info::find (const vmap& extra_vars, const std::string& vname) const
@@ -2482,8 +3100,7 @@
                                    : *iter->second;
 }
 
-#endif
-
+#endif /* if HAVE_JIT */
 
 DEFUN (jit_failure_count, args, nargout,
        "-*- texinfo -*-\n\
@@ -2499,7 +3116,7 @@
 @seealso{jit_enable, jit_startcnt, debug_jit}\n\
 @end deftypefn")
 {
-#if defined (HAVE_LLVM)
+#if defined (HAVE_JIT)
   return SET_INTERNAL_VARIABLE (jit_failure_count);
 #else
   warning ("jit_failure_count: JIT compiling not available in this version of Octave");
@@ -2521,7 +3138,7 @@
 @seealso{jit_enable, jit_startcnt}\n\
 @end deftypefn")
 {
-#if defined (HAVE_LLVM)
+#if defined (HAVE_JIT)
   return SET_INTERNAL_VARIABLE (debug_jit);
 #else
   warning ("debug_jit: JIT compiling not available in this version of Octave");
@@ -2542,7 +3159,7 @@
 @seealso{jit_startcnt, debug_jit}\n\
 @end deftypefn")
 {
-#if defined (HAVE_LLVM)
+#if defined (HAVE_JIT)
   return SET_INTERNAL_VARIABLE (jit_enable);
 #else
   warning ("jit_enable: JIT compiling not available in this version of Octave");
@@ -2566,7 +3183,7 @@
 @seealso{jit_enable, debug_jit}\n\
 @end deftypefn")
 {
-#if defined (HAVE_LLVM)
+#if defined (HAVE_JIT)
   return SET_INTERNAL_VARIABLE_WITH_LIMITS (jit_startcnt, 1,
                                             std::numeric_limits<int>::max ());
 #else
diff --git a/libinterp/corefcn/pt-jit.h b/libinterp/corefcn/pt-jit.h
--- a/libinterp/corefcn/pt-jit.h
+++ b/libinterp/corefcn/pt-jit.h
@@ -25,12 +25,16 @@
 #if !defined (octave_pt_jit_h)
 #define octave_pt_jit_h 1
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 
 #include "jit-ir.h"
 #include "pt-walk.h"
 #include "symtab.h"
 
+#ifdef HAVE_GCCJIT
+#include "libgccjit++.h"
+#endif
+
 class octave_value_list;
 
 // Convert from the parse tree (AST) to the low level Octave IR.
@@ -69,7 +73,9 @@
 
   jit_factory& get_factory (void) { return factory; }
 
+#ifdef HAVE_LLVM
   llvm::Function *get_function (void) const { return function; }
+#endif
 
   const variable_map &get_variable_map (void) const { return vmap; }
 
@@ -180,7 +186,9 @@
 
   jit_block *block;
 
+#ifdef HAVE_LLVM
   llvm::Function *function;
+#endif
 
   jit_block_list blocks;
 
@@ -242,7 +250,81 @@
   void finish_breaks (jit_block *dest, const block_list& lst);
 };
 
+// Convert from the low level Octave IR to libgccjit
+#ifdef HAVE_GCCJIT
+class
+jit_convert_gcc : public jit_ir_walker
+{
+public:
+  jit_convert_gcc ();
+  ~jit_convert_gcc ();
+
+  gcc_jit_result *convert_loop (const jit_block_list& blocks,
+                                const std::list<jit_value *>& constants);
+
+#define JIT_METH(clname)                        \
+  virtual void visit (jit_ ## clname&);
+
+  JIT_VISIT_IR_CLASSES;
+
+private:
+  void visit (jit_value *jvalue)
+  {
+    return visit (*jvalue);
+  }
+
+  void visit (jit_value &jvalue)
+  {
+    jvalue.accept (*this);
+  }
+
+#if 0
+  gccjit::lvalue as_lvalue (jit_value *);
+#endif
+  gccjit::rvalue as_rvalue (jit_value *);
+
+  void add_assignment_for_insn (jit_instruction &insn,
+                                gccjit::rvalue val);
+
+  gccjit::block get_block_for_edge (jit_block *src, jit_block *dest);
+
+  gccjit::block get_current_block ();
+  void push_block (gccjit::block block);
+  void pop_block ();
+
+  bool converting_function;
+
+  // Inputs (used internally by callback):
+  const jit_block_list *m_blocks;
+  const std::list<jit_value *> *m_constants;
+
+  // Internal state:
+  gccjit::context m_ctxt;
+  gccjit::function m_func;
+
+  /* We have a single param, confusingly named "params" (an array).  */
+  gccjit::param params;
+
+  // 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;
+
+  std::vector<gccjit::lvalue> m_extracted_params;
+  std::map<jit_block *, gccjit::block> m_block_map;
+  std::map<std::pair<jit_block *, jit_block *>, gccjit::block> m_blocks_for_edges;
+  std::map<jit_instruction *, gccjit::lvalue> m_locals_for_insns;
+
+  std::map<jit_value *, gccjit::rvalue> m_rvalues;
+
+  std::stack<gccjit::block> m_block_stack;
+
+  bool m_with_comments;
+  bool m_log_visits;
+};
+#endif // #ifdef HAVE_GCCJIT
+
 // Convert from the low level Octave IR to LLVM
+#if HAVE_LLVM
 class
 jit_convert_llvm : public jit_ir_walker
 {
@@ -299,6 +381,7 @@
     jvalue.accept (*this);
   }
 };
+#endif /* HAVE_LLVM */
 
 // type inference and SSA construction on the low level Octave IR
 class
@@ -362,11 +445,13 @@
   static bool execute (octave_user_function& fcn, const octave_value_list& args,
                        octave_value_list& retval);
 
+#ifdef HAVE_LLVM
   llvm::ExecutionEngine *get_engine (void) const { return engine; }
 
   llvm::Module *get_module (void) const { return module; }
 
   void optimize (llvm::Function *fn);
+#endif
 private:
   tree_jit (void);
 
@@ -385,10 +470,12 @@
 
   size_t trip_count (const octave_value& bounds) const;
 
+#ifdef HAVE_LLVM
   llvm::Module *module;
   llvm::PassManager *module_pass_manager;
   llvm::FunctionPassManager *pass_manager;
   llvm::ExecutionEngine *engine;
+#endif
 };
 
 class
@@ -434,13 +521,19 @@
 
   octave_value find (const vmap& extra_vars, const std::string& vname) const;
 
+#ifdef HAVE_LLVM
   llvm::ExecutionEngine *engine;
+#endif
   jited_function function;
+#ifdef HAVE_LLVM
   llvm::Function *llvm_function;
-
+#endif
+#ifdef HAVE_GCCJIT
+  gcc_jit_result *gccjit_result;
+#endif
   std::vector<std::pair<std::string, bool> > arguments;
   type_bound_vector bounds;
 };
 
+#endif /* ifdef HAVE_JIT */
 #endif
-#endif
diff --git a/libinterp/link-deps.mk b/libinterp/link-deps.mk
--- a/libinterp/link-deps.mk
+++ b/libinterp/link-deps.mk
@@ -15,6 +15,7 @@
   $(X11_LIBS) \
   $(CARBON_LIBS) \
   $(GL2PS_LIBS) \
+  $(LIBGCCJIT_LIBS) \
   $(LLVM_LIBS) \
   $(JAVA_LIBS) \
   $(LAPACK_LIBS)
@@ -24,6 +25,7 @@
   $(HDF5_LDFLAGS) \
   $(Z_LDFLAGS) \
   $(FFTW_XLDFLAGS) \
+  $(LIBGCCJIT_LDFLAGS) \
   $(LLVM_LDFLAGS)
 
 OCT_LINK_DEPS =
diff --git a/libinterp/octave-value/ov-usr-fcn.h b/libinterp/octave-value/ov-usr-fcn.h
--- a/libinterp/octave-value/ov-usr-fcn.h
+++ b/libinterp/octave-value/ov-usr-fcn.h
@@ -44,7 +44,7 @@
 class tree_expression;
 class tree_walker;
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 class jit_function_info;
 #endif
 
@@ -404,11 +404,11 @@
       return false;
   }
 
-#ifdef HAVE_LLVM
+  #ifdef HAVE_JIT
   jit_function_info *get_info (void) { return jit_info; }
 
   void stash_info (jit_function_info *info) { jit_info = info; }
-#endif
+  #endif
 
 #if 0
   void print_symtab_info (std::ostream& os) const;
@@ -499,9 +499,9 @@
   // pointer to the current unwind_protect frame of this function.
   unwind_protect *curr_unwind_protect_frame;
 
-#ifdef HAVE_LLVM
+  //#ifdef HAVE_LLVM
   jit_function_info *jit_info;
-#endif
+  //#endif
 
   void maybe_relocate_end_internal (void);
 
diff --git a/libinterp/parse-tree/pt-eval.cc b/libinterp/parse-tree/pt-eval.cc
--- a/libinterp/parse-tree/pt-eval.cc
+++ b/libinterp/parse-tree/pt-eval.cc
@@ -313,7 +313,7 @@
 
   octave_value rhs = expr->rvalue1 ();
 
-#if HAVE_LLVM
+#if HAVE_JIT
   if (tree_jit::execute (cmd, rhs))
     return;
 #endif
@@ -1074,7 +1074,7 @@
   if (error_state)
     return;
 
-#if HAVE_LLVM
+#if HAVE_JIT
   if (tree_jit::execute (cmd))
     return;
 #endif
diff --git a/libinterp/parse-tree/pt-loop.cc b/libinterp/parse-tree/pt-loop.cc
--- a/libinterp/parse-tree/pt-loop.cc
+++ b/libinterp/parse-tree/pt-loop.cc
@@ -50,7 +50,7 @@
   delete list;
   delete lead_comm;
   delete trail_comm;
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
   delete compiled;
 #endif
 }
@@ -101,7 +101,7 @@
   delete list;
   delete lead_comm;
   delete trail_comm;
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
   delete compiled;
 #endif
 }
diff --git a/libinterp/parse-tree/pt-loop.h b/libinterp/parse-tree/pt-loop.h
--- a/libinterp/parse-tree/pt-loop.h
+++ b/libinterp/parse-tree/pt-loop.h
@@ -48,7 +48,7 @@
   tree_while_command (int l = -1, int c = -1)
     : tree_command (l, c), expr (0), list (0), lead_comm (0),
       trail_comm (0)
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
       , compiled (0)
 #endif
   { }
@@ -59,7 +59,7 @@
                       int l = -1, int c = -1)
     : tree_command (l, c), expr (e), list (0), lead_comm (lc),
       trail_comm (tc)
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
       , compiled (0)
 #endif
   { }
@@ -70,7 +70,7 @@
                       int l = -1, int c = -1)
     : tree_command (l, c), expr (e), list (lst), lead_comm (lc),
       trail_comm (tc)
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
       , compiled (0)
 #endif
   { }
@@ -90,7 +90,7 @@
 
   void accept (tree_walker& tw);
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
   // some functions use by tree_jit
   jit_info *get_info (void) const
   {
@@ -119,7 +119,7 @@
 
 private:
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
   // compiled version of the loop
   jit_info *compiled;
 #endif
@@ -179,7 +179,7 @@
   tree_simple_for_command (int l = -1, int c = -1)
     : tree_command (l, c), parallel (false), lhs (0), expr (0),
       maxproc (0), list (0), lead_comm (0), trail_comm (0)
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
       , compiled (0)
 #endif
   { }
@@ -194,7 +194,7 @@
     : tree_command (l, c), parallel (parallel_arg), lhs (le),
       expr (re), maxproc (maxproc_arg), list (lst),
       lead_comm (lc), trail_comm (tc)
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
       , compiled (0)
 #endif
   { }
@@ -220,7 +220,7 @@
 
   void accept (tree_walker& tw);
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
   // some functions use by tree_jit
   jit_info *get_info (void) const
   {
diff --git a/run-octave.in b/run-octave.in
--- a/run-octave.in
+++ b/run-octave.in
@@ -72,7 +72,11 @@
   elif [ "x$1" = "x-strace" ]; then
     driver="strace -o octave.trace"
     shift
-  elif [ "x$1" = "x-cli" ]; then
+  fi
+fi
+
+if [ $# -gt 0 ]; then
+  if [ "x$1" = "x-cli" ]; then
     octave_executable="$builddir/src/octave-cli"
     shift
   fi
diff --git a/test/jit.tst b/test/jit.tst
--- a/test/jit.tst
+++ b/test/jit.tst
@@ -19,14 +19,14 @@
 ## Author: Max Brister <max@2bass.com>
 
 ## Turn on JIT and set defaults before running tests
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! 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
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! for i=1:1e6
 %!   if (i < 5)
@@ -38,7 +38,7 @@
 %! assert (i, 1);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! while (1)
 %!   if (1)
@@ -49,14 +49,14 @@
 %! endwhile
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! do
 %!   break;
 %! until (0)
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! do
 %!   if (1)
@@ -65,7 +65,7 @@
 %! until (0)
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! i=1;
 %! do
@@ -75,7 +75,7 @@
 %! assert (i, 1);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! for i=1:1e6
 %!   if (i == 100)
@@ -86,7 +86,7 @@
 %! assert (jit_failure_count, 0);
 
 ## Also test parfor keyword
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! parfor i=1:1e6
 %!   if (i == 100)
@@ -96,7 +96,7 @@
 %! assert (i, 100);
 %! assert (jit_failure_count, 0);
 ## Test some switch statements
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! do
 %!   switch (1)
@@ -104,7 +104,7 @@
 %! until(1)
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! do
 %!   switch (1)
@@ -114,7 +114,7 @@
 %! until(1)
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! do
 %!   switch (1)
@@ -124,7 +124,7 @@
 %! until(1)
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! do
 %!   switch (1)
@@ -161,8 +161,7 @@
 %! assert (b, 1);
 %! assert (jit_failure_count, 0);
 
-## Some more complex calculations
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! inc = 1e-5;
 %! result = 0;
@@ -172,7 +171,7 @@
 %! assert (abs (result - 1/9) < 1e-5);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! inc = 1e-5;
 %! result = 0;
@@ -183,7 +182,7 @@
 %! assert (abs (result - 1/9) < 1e-5);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! temp = 1+1i;
 %! nan = NaN;
@@ -195,7 +194,7 @@
 %! assert (imag (temp), 0);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! temp = 1+1i;
 %! nan = NaN+1i;
@@ -208,7 +207,7 @@
 %! assert (imag (temp), 0);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! temp = 1+1i;
 %! while (1)
@@ -218,7 +217,7 @@
 %! assert (temp, 5+5i);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! nr = 1001;
 %! mat = zeros (1, nr);
@@ -228,7 +227,7 @@
 %! assert (mat == 1:nr);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! nr = 1001;
 %! mat = 1:nr;
@@ -240,7 +239,7 @@
 %! assert (sum (mat) == total);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! nr = 1001;
 %! mat = [3 1 5];
@@ -290,13 +289,13 @@
 %!  endif
 %!endfunction
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! test_set = gen_test (10000);
 %! assert (all (vectorized (test_set, 3) == loopy (test_set, 3)));
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! niter = 1001;
 %! i = 0;
@@ -306,7 +305,7 @@
 %! assert (i == niter);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! niter = 1001;
 %! result = 0;
@@ -317,8 +316,11 @@
 %! assert (result == m(end) * niter);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
-%! jit_failure_count (0)
+## This one is currently failing for some reason
+##          result ==   505000
+##   sum (sum (m)) == 50005000
+##
+%!testif 0
 %! ndim = 100;
 %! result = 0;
 %! m = zeros (ndim);
@@ -330,10 +332,13 @@
 %!    endfor
 %!   i = i + 1;
 %! endwhile
+%! disp (m)
+%! disp (result)
+%! disp (sum (sum (m)))
 %! assert (result == sum (sum (m)));
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif 0
 %! jit_failure_count (0)
 %! ndim = 100;
 %! m = zeros (ndim);
@@ -349,7 +354,7 @@
 %! assert (all (m == m2));
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif 0
 %! jit_failure_count (0)
 %! ndim = 2;
 %! m = zeros (ndim, ndim, ndim, ndim);
@@ -385,7 +390,7 @@
 %! end_unwind_protect
 %!endfunction
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! lasterr ("");
 %! try
@@ -394,7 +399,7 @@
 %! assert (strcmp (lasterr (), "division by zero"));
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! while (1)
 %!   a = 0;
@@ -404,7 +409,7 @@
 %! assert (result, 0);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! m = zeros (2, 1001);
 %! for i=1:1001
@@ -417,7 +422,7 @@
 %! assert (m, m2);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! m = [1 2 3];
 %! for i=1:1001
@@ -427,7 +432,7 @@
 %! assert (m == sin ([1  2 3]));
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! i = 0;
 %! while i < 10
@@ -436,7 +441,7 @@
 %! assert (i == 10);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! i = 0;
 %! while i < 10
@@ -444,9 +449,9 @@
 %! endwhile
 %! assert (i == 10);
 %! assert (a == 10);
-%! jit_failure_count (0)
+%! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! i = 0;
 %! while i < 10
@@ -456,7 +461,7 @@
 %! assert (a == 9);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! num = 2;
 %! a = zeros (1, num);
@@ -480,7 +485,7 @@
 %!   endif;
 %! endwhile
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! lasterr ("");
 %! try
@@ -496,7 +501,7 @@
 %!  endwhile
 %!endfunction
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! assert (test_overload (1), 1);
 %! assert (test_overload ([1 2]), [1 2]);
@@ -518,12 +523,12 @@
 %!  endwhile
 %!endfunction
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! assert (bubble (), [1 2 3]);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! a = 0;
 %! b = 1;
@@ -536,7 +541,7 @@
 %! assert (b, 1);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! a = [1+1i 1+2i];
 %! b = 0;
@@ -553,7 +558,7 @@
 %!  endfor
 %!endfunction
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! lasterr ("");
 %! try
@@ -565,14 +570,14 @@
 %!shared id
 %! id = @(x) x;
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! assert (id (1), 1);
 %! assert (id (1+1i), 1+1i);
 %! assert (id (1, 2), 1);
 %! assert (jit_failure_count, 0);
 
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! jit_failure_count (0)
 %! lasterr ("");
 %! try
@@ -582,7 +587,7 @@
 %! assert (jit_failure_count, 0);
 
 ## Restore JIT settings
-%!testif HAVE_LLVM
+%!testif HAVE_JIT
 %! global __old_jit_enable__;
 %! global __old_jit_startcnt__;
 %! jit_enable (__old_jit_enable__);
