diff libinterp/corefcn/pt-jit.cc @ 20654:b65888ec820e draft default tip gccjit

dmalcom gcc jit import
author Stefan Mahr <dac922@gmx.de>
date Fri, 27 Feb 2015 16:59:36 +0100
parents d35201e5ce5d
children
line wrap: on
line diff
--- a/libinterp/corefcn/pt-jit.cc	Tue Oct 13 11:40:05 2015 +0100
+++ b/libinterp/corefcn/pt-jit.cc	Fri Feb 27 16:59:36 2015 +0100
@@ -38,7 +38,7 @@
 #include "symtab.h"
 #include "variables.h"
 
-#ifdef HAVE_LLVM
+#ifdef HAVE_JIT
 
 static bool Vdebug_jit = false;
 
@@ -48,6 +48,7 @@
 
 static int Vjit_failcnt = 0;
 
+#ifdef HAVE_LLVM
 #include <llvm/Analysis/CallGraph.h>
 #include <llvm/Analysis/Passes.h>
 
@@ -101,6 +102,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
@@ -1295,7 +1298,565 @@
     }
 }
 
+// -------------------- jit_convert_gcc --------------------
+#ifdef HAVE_GCCJIT
+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");
+}
+#endif /* HAVE_GCCJIT */
+
 // -------------------- jit_convert_llvm --------------------
+
+#ifdef HAVE_LLVM
+
 llvm::Function *
 jit_convert_llvm::convert_loop (llvm::Module *module,
                                 const jit_block_list& blocks,
@@ -1361,7 +1922,11 @@
   jit_return *ret = dynamic_cast<jit_return *> (final_block->back ());
   assert (ret);
 
-  creating = jit_function (module, jit_convention::internal,
+  creating = jit_function (module,
+#ifdef HAVE_GCCJIT
+                           gccjit::context (), // FIXME?
+#endif
+                           jit_convention::internal,
                            "foobar", ret->result_type (), args);
   function = creating.to_llvm ();
 
@@ -1649,6 +2214,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)
@@ -2052,6 +2619,7 @@
 bool
 tree_jit::initialize (void)
 {
+#ifdef HAVE_LLVM
   if (engine)
     return true;
 
@@ -2089,8 +2657,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;
 }
@@ -2177,7 +2750,7 @@
   return 0;
 }
 
-
+#ifdef HAVE_LLVM
 void
 tree_jit::optimize (llvm::Function *fn)
 {
@@ -2200,8 +2773,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)
@@ -2217,6 +2792,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 ();
@@ -2253,7 +2843,11 @@
       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,
+#ifdef HAVE_GCCJIT
+                              gccjit::context (), // FIXME
+#endif
+                              jit_convention::internal, wrapper_name,
                               any_t, wrapper_args);
 
       llvm::BasicBlock *wrapper_body = wrapper.new_block ();
@@ -2318,6 +2912,7 @@
       raw_fn.erase ();
     }
 }
+#endif /* ifdef HAVE_JIT */
 
 bool
 jit_function_info::execute (const octave_value_list& ov_args,
@@ -2363,14 +2958,21 @@
 }
 
 // -------------------- jit_info --------------------
+#ifdef HAVE_LLVM
 jit_info::jit_info (tree_jit& tjit, tree& tee)
   : engine (tjit.get_engine ()), function (0), llvm_function (0)
+#ifdef HAVE_GCCJIT
+    , gccjit_result (NULL)
+#endif
 {
   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)
+#ifdef HAVE_GCCJIT
+    , gccjit_result (NULL)
+#endif
 {
   compile (tjit, tee, jit_typeinfo::type_of (for_bounds));
 }
@@ -2379,7 +2981,12 @@
 {
   if (llvm_function)
     llvm_function->eraseFromParent ();
+#ifdef HAVE_GCCJIT
+  if (gccjit_result)
+    gcc_jit_result_release (gccjit_result);
+#endif
 }
+#endif
 
 bool
 jit_info::execute (const vmap& extra_vars) const
@@ -2435,12 +3042,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 ());
 
@@ -2456,6 +3074,13 @@
         }
 
       jit_factory& factory = conv.get_factory ();
+
+#ifdef HAVE_GCCJIT
+      jit_convert_gcc to_gcc;
+      gccjit_result = to_gcc.convert_loop (infer.get_blocks (),
+                                           factory.constants ());
+#endif
+
       jit_convert_llvm to_llvm;
       llvm_function = to_llvm.convert_loop (tjit.get_module (),
                                             infer.get_blocks (),
@@ -2474,7 +3099,19 @@
       Vjit_failcnt++;
 
     }
-
+#ifdef HAVE_GCCJIT
+  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
+#endif
   if (llvm_function)
     {
       if (Vdebug_jit)
@@ -2497,6 +3134,7 @@
       function = reinterpret_cast<jited_function> (void_fn);
     }
 }
+#endif
 
 octave_value
 jit_info::find (const vmap& extra_vars, const std::string& vname) const
@@ -2506,16 +3144,16 @@
                                    : *iter->second;
 }
 
-#endif
-
-#if defined (HAVE_LLVM)
-#define UNUSED_WITHOUT_LLVM(x) x
+#endif /* if HAVE_JIT */
+
+#if defined (HAVE_JIT)
+#define UNUSED_WITHOUT_JIT(x) x
 #else
-#define UNUSED_WITHOUT_LLVM(x) x GCC_ATTR_UNUSED
+#define UNUSED_WITHOUT_JIT(x) x GCC_ATTR_UNUSED
 #endif
 
-DEFUN (jit_failcnt, UNUSED_WITHOUT_LLVM (args),
-       UNUSED_WITHOUT_LLVM (nargout),
+DEFUN (jit_failcnt, UNUSED_WITHOUT_JIT (args),
+       UNUSED_WITHOUT_JIT (nargout),
        "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {@var{val} =} jit_failcnt ()\n\
 @deftypefnx {Built-in Function} {@var{old_val} =} jit_failcnt (@var{new_val})\n\
@@ -2529,7 +3167,7 @@
 @seealso{jit_enable, jit_startcnt, debug_jit}\n\
 @end deftypefn")
 {
-#if defined (HAVE_LLVM)
+#if defined (HAVE_JIT)
   return SET_INTERNAL_VARIABLE (jit_failcnt);
 #else
   warning ("jit_failcnt: JIT compiling not available in this version of Octave");
@@ -2537,8 +3175,8 @@
 #endif
 }
 
-DEFUN (debug_jit, UNUSED_WITHOUT_LLVM (args),
-       UNUSED_WITHOUT_LLVM (nargout),
+DEFUN (debug_jit, UNUSED_WITHOUT_JIT (args),
+       UNUSED_WITHOUT_JIT (nargout),
        "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {@var{val} =} debug_jit ()\n\
 @deftypefnx {Built-in Function} {@var{old_val} =} debug_jit (@var{new_val})\n\
@@ -2552,7 +3190,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");
@@ -2560,8 +3198,8 @@
 #endif
 }
 
-DEFUN (jit_enable, UNUSED_WITHOUT_LLVM (args),
-       UNUSED_WITHOUT_LLVM (nargout),
+DEFUN (jit_enable, UNUSED_WITHOUT_JIT (args),
+       UNUSED_WITHOUT_JIT (nargout),
        "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {@var{val} =} jit_enable ()\n\
 @deftypefnx {Built-in Function} {@var{old_val} =} jit_enable (@var{new_val})\n\
@@ -2574,7 +3212,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");
@@ -2582,8 +3220,8 @@
 #endif
 }
 
-DEFUN (jit_startcnt, UNUSED_WITHOUT_LLVM (args),
-       UNUSED_WITHOUT_LLVM (nargout),
+DEFUN (jit_startcnt, UNUSED_WITHOUT_JIT (args),
+       UNUSED_WITHOUT_JIT (nargout),
        "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {@var{val} =} jit_startcnt ()\n\
 @deftypefnx {Built-in Function} {@var{old_val} =} jit_startcnt (@var{new_val})\n\
@@ -2601,7 +3239,7 @@
 @seealso{jit_enable, jit_failcnt, 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