# HG changeset patch
# User Gene Harvey <gharveymn@gmail.com>
# Date 1562602709 18000
#      Mon Jul 08 11:18:29 2019 -0500
# Branch jitwork_oldcrash
# Node ID fa22ddcdc79688f5d8ea3164aa34f6785541ed79
# Parent  e2e895f8a6c2069a7f2f1e71fc145b14eb3637a6
fix crash when running jit on older versions of LLVM

* jit-typeinfo.cc (jit_function::jit_function ()): Add initializers.
(jit_function::jit_function (jit_module *,...)): Add initializers. Use
new member variable.
(jit_function::jit_function (const jit_function&,...)): Add inits.
(jit_function::name): Remove.
(jit_function::call): Add module parameter. Use function decl lookup
in module.
(jit_typeinfo::jit_typeinfo): Use std::string rather than llvm::Twine.
Pass module to jit_function::call.
(jit_typeinfo::create_external): Use string rather than Twine.
(jit_typeinfo::do_insert_error_check,
jit_typeinfo::do_insert_interrupt_check): Look for global variable
definition in module before creating a new one.
(jit_typeinfo::register_generic,
jit_typeinfo::mirror_binary): Pass module to jit_function::call.

jit-typeinfo.h (jit_function::jit_function (const jit_function&):
Use default keyword.
(jit_function::operator=): Define to placate compiler whinging.
(jit_function::name): Make constexpr. Return member variable.
(jit_function::call): Add module parameter.
(jit_function::m_llvm_ftype, jit_function::m_name): New member vars.
(jit_operation::overload, jit_operation::result): Remove
unnecessary overload.
(jit_typeinfo::insert_error_check,
jit_typeinfo::insert_interrupt_check,
jit_typeinfo::do_insert_error_check,
jit_typeinfo::do_insert_interrupt_check): Add module parameter.
(jit_typeinfo::create_external, jit_typeinfo::create_internal): Remove
unnecessary overload. Use std::string instead of llvm::Twine.

pt-jit.cc (jit_convert_llvm::convert_loop): Remove parameter. Use
member variable.
(jit_convert_llvm::convert_function): Use member variable. Pass module
to jit_function::call.
(jit_convert_llvm::visit): Pass module to jit_function::call
and jit_typeinfo::insert_error_check.
(tree_jit::do_getPointerToNamedFunction):
Defer to tree_jit::do_getSymbolAddress
(tree_jit::do_getSymbolAddress): Search for module containing
definition of llvm function.
(jit_module::create_llvm_function,
jit_module::create_global_variable): Use string instead of Twine. Add
function of map after creation.
(jit_function_info::jit_function_info, jit_info::compile):
Adjust jit_convert_llvm usage. Pass module to jit_function::call.

pt-jit.h: New include.
(jit_convert_llvm::jit_convert_llvm): New constructor.
(jit_convert_llvm::convert_loop, jit_convert_llvm::convert_function):
Remove parameter.
(jit_convert_llvm::m_module): New member variable.
(jit_module): Use std::string instead of llvm::Twine.
(jit_module::llvm_function_map, jit_module::llvm_globvar_map):
New directives.
(jit_module::m_function_decl_map, jit_module::m_function_map,
jit_module::m_globvar): New member variables.

pt-jit.cc, pt-jit.h (jit_module::create_llvm_function_decl,
jit_module::find_llvm_function, jit_module::find_llvm_function_decl,
jit_module::find_globvar, jit_module::get_name): New functions.

diff -r e2e895f8a6c2 -r fa22ddcdc796 libinterp/parse-tree/jit-typeinfo.cc
--- a/libinterp/parse-tree/jit-typeinfo.cc	Thu Jun 27 00:49:30 2019 -0500
+++ b/libinterp/parse-tree/jit-typeinfo.cc	Mon Jul 08 11:18:29 2019 -0500
@@ -556,16 +556,27 @@
 
   // -------------------- jit_function --------------------
   jit_function::jit_function ()
-    : m_module (nullptr), m_llvm_function (nullptr), m_result (nullptr),
-      m_call_conv (jit_convention::length), m_can_error (false)
+    : m_module (nullptr),
+      m_llvm_function (nullptr),
+      m_llvm_ftype (nullptr),
+      m_name (""),
+      m_result (nullptr),
+      m_call_conv (jit_convention::length),
+      m_can_error (false)
   { }
 
-  jit_function::jit_function (const jit_module *amodule,
+  jit_function::jit_function (jit_module *amodule,
                               jit_convention::type acall_conv,
-                              const llvm::Twine& aname, jit_type *aresult,
+                              std::string aname, jit_type *aresult,
                               const std::vector<jit_type *>& aargs)
-    : m_module (amodule), m_result (aresult), m_args (aargs),
-      m_call_conv (acall_conv), m_can_error (false)
+    : m_module (amodule),
+      m_llvm_function (nullptr),
+      m_llvm_ftype (nullptr),
+      m_name (std::move (aname)),
+      m_result (aresult),
+      m_args (aargs),
+      m_call_conv (acall_conv),
+      m_can_error (false)
   {
     llvm::SmallVector<llvm::Type *, 15> llvm_args;
 
@@ -591,8 +602,8 @@
         llvm_args.push_back (argty);
       }
 
-    llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false);
-    m_llvm_function = m_module->create_llvm_function (ft, aname);
+    m_llvm_ftype = llvm::FunctionType::get (rtype, llvm_args, false);
+    m_llvm_function = m_module->create_llvm_function (m_llvm_ftype, m_name);
 
     if (sret ())
       {
@@ -616,14 +627,13 @@
 
   jit_function::jit_function (const jit_function& fn, jit_type *aresult,
                               const std::vector<jit_type *>& aargs)
-    : m_module (fn.m_module), m_llvm_function (fn.m_llvm_function),
-      m_result (aresult), m_args (aargs), m_call_conv (fn.m_call_conv),
-      m_can_error (fn.m_can_error)
-  { }
-
-  jit_function::jit_function (const jit_function& fn)
-    : m_module (fn.m_module), m_llvm_function (fn.m_llvm_function),
-      m_result (fn.m_result), m_args (fn.m_args), m_call_conv (fn.m_call_conv),
+    : m_module (fn.m_module),
+      m_llvm_function (fn.m_llvm_function),
+      m_llvm_ftype (fn.m_llvm_ftype),
+      m_name (fn.m_name),
+      m_result (aresult),
+      m_args (aargs),
+      m_call_conv (fn.m_call_conv),
       m_can_error (fn.m_can_error)
   { }
 
@@ -637,12 +647,6 @@
     m_llvm_function = 0;
   }
 
-  std::string
-  jit_function::name (void) const
-  {
-    return m_llvm_function->getName ();
-  }
-
   llvm::BasicBlock *
   jit_function::new_block (const std::string& aname,
                            llvm::BasicBlock *insert_before)
@@ -652,7 +656,7 @@
   }
 
   llvm::Value *
-  jit_function::call (llvm::IRBuilderD& builder,
+  jit_function::call (jit_module *module, llvm::IRBuilderD& builder,
                       const std::vector<jit_value *>& in_args) const
   {
     if (! valid ())
@@ -663,11 +667,11 @@
     for (size_t i = 0; i < in_args.size (); ++i)
       llvm_args[i] = in_args[i]->to_llvm ();
 
-    return call (builder, llvm_args);
+    return call (module, builder, llvm_args);
   }
 
   llvm::Value *
-  jit_function::call (llvm::IRBuilderD& builder,
+  jit_function::call (jit_module *module, llvm::IRBuilderD& builder,
                       const std::vector<llvm::Value *>& in_args) const
   {
     if (! valid ())
@@ -710,7 +714,23 @@
         llvm_args.push_back (arg);
       }
 
-    llvm::CallInst *callinst = builder.CreateCall (m_llvm_function, llvm_args);
+    llvm::Function *fcn = m_llvm_function;
+    if (m_module != module)
+      {
+        // lookup function def in the module
+        fcn = module->find_llvm_function (m_name);
+
+        // if not found check the declarations
+        if (! fcn)
+          {
+            fcn = module->find_llvm_function_decl (m_name);
+
+            // if not declared then create one
+            if (! fcn)
+              fcn = module->create_llvm_function_decl (m_llvm_ftype, m_name);
+          }
+      }
+    llvm::CallInst *callinst = builder.CreateCall (fcn, llvm_args);
     llvm::Value *ret = callinst;
 
     if (sret ())
@@ -1011,7 +1031,8 @@
     llvm::Value *nelem = llvm::ConstantInt::get (m_typeinfo.m_index_t,
                                                  types.size () - 1);
     llvm::Value *mat = fn->argument (builder, 0);
-    llvm::Value *ret = m_paren_scalar->call (builder, mat, array, nelem);
+    llvm::Value *ret = m_paren_scalar->call (module, builder, mat, array,
+                                             nelem);
     fn->do_return (builder, ret);
     module->finalizeObject ();
 
@@ -1072,7 +1093,8 @@
 
     llvm::Value *mat = fn->argument (builder, 0);
     llvm::Value *value = fn->argument (builder, types.size () - 1);
-    llvm::Value *ret = m_paren_scalar->call (builder, mat, array, nelem, value);
+    llvm::Value *ret = m_paren_scalar->call (module, builder, mat, array,
+                                             nelem, value);
     fn->do_return (builder, ret);
     module->finalizeObject ();
 
@@ -1302,8 +1324,8 @@
 
     for (int op = 0; op < octave_value::num_binary_ops; ++op)
       {
-        const llvm::Twine &fn_name =
-          "octave_jit_binary_any_any_" + llvm::Twine (op);
+        std::string fn_name =
+          "octave_jit_binary_any_any_" + std::to_string (op);
 
         fn = create_internal (fn_name, m_any, m_any, m_any);
         fn.mark_can_error ();
@@ -1312,7 +1334,8 @@
         llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op,
                            std::numeric_limits<octave_value::binary_op>::is_signed);
         llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int);
-        llvm::Value *ret = any_binary.call (m_builder, op_as_llvm,
+        llvm::Value *ret = any_binary.call (m_base_jit_module, m_builder,
+                                            op_as_llvm,
                                             fn.argument (m_builder, 0),
                                             fn.argument (m_builder, 1));
         fn.do_return (m_builder, ret);
@@ -1641,7 +1664,7 @@
       m_builder.CreateCondBr (check, error_block, normal_block);
 
       m_builder.SetInsertPoint (error_block);
-      gripe_nantl.call (m_builder);
+      gripe_nantl.call (m_base_jit_module, m_builder);
       m_builder.CreateBr (normal_block);
       m_builder.SetInsertPoint (normal_block);
 
@@ -1668,7 +1691,8 @@
       llvm::Value *base = fn.argument (m_builder, 0);
       llvm::Value *limit = fn.argument (m_builder, 1);
       llvm::Value *inc = fn.argument (m_builder, 2);
-      llvm::Value *nelem = compute_nelem.call (m_builder, base, limit, inc);
+      llvm::Value *nelem = compute_nelem.call (m_base_jit_module, m_builder,
+                                               base, limit, inc);
 
       llvm::Constant *dzero = llvm::ConstantFP::get (m_scalar_t, 0);
       llvm::Constant *izero = llvm::ConstantInt::get (m_index_t, 0);
@@ -1717,7 +1741,7 @@
       m_builder.CreateCondBr (cond, conv_error, normal);
 
       m_builder.SetInsertPoint (conv_error);
-      ginvalid_index.call (m_builder);
+      ginvalid_index.call (m_base_jit_module, m_builder);
       m_builder.CreateBr (done);
 
       m_builder.SetInsertPoint (normal);
@@ -1730,7 +1754,8 @@
       m_builder.CreateCondBr (cond, bounds_error, success);
 
       m_builder.SetInsertPoint (bounds_error);
-      gindex_range.call (m_builder, one_int, one_int, int_idx, len);
+      gindex_range.call (m_base_jit_module, m_builder, one_int, one_int,
+                         int_idx, len);
       m_builder.CreateBr (done);
 
       m_builder.SetInsertPoint (success);
@@ -1780,7 +1805,7 @@
       llvm::BasicBlock *normal = fn.new_block ("normal", done);
       m_builder.CreateCondBr (cond, conv_error, normal);
       m_builder.SetInsertPoint (conv_error);
-      ginvalid_index.call (m_builder);
+      ginvalid_index.call (m_base_jit_module, m_builder);
       m_builder.CreateBr (done);
 
       m_builder.SetInsertPoint (normal);
@@ -1798,8 +1823,9 @@
 
       // resize on out of bounds access
       m_builder.SetInsertPoint (bounds_error);
-      llvm::Value *resize_result = resize_paren_subsasgn.call (m_builder, mat,
-                                                               int_idx, value);
+      llvm::Value *resize_result
+          = resize_paren_subsasgn.call (m_base_jit_module, m_builder, mat,
+                                        int_idx, value);
       m_builder.CreateBr (done);
 
       m_builder.SetInsertPoint (success);
@@ -1997,10 +2023,9 @@
   // create a function with an external calling convention
   // forces the function pointer to be specified
   template <typename fn_ptr_type> jit_function
-  jit_typeinfo::create_external (fn_ptr_type fn,
-                                 const llvm::Twine& name,
+  jit_typeinfo::create_external (fn_ptr_type fn, const std::string& name,
                                  jit_type *ret,
-                                 const std::vector<jit_type *>& args) const
+                                 const signature_vec& args) const
   {
     jit_function retval (m_base_jit_module, jit_convention::external,
                          name, ret, args);
@@ -2144,15 +2169,41 @@
   }
 
   llvm::Value *
-  jit_typeinfo::do_insert_error_check (llvm::IRBuilderD& abuilder)
+  jit_typeinfo::do_insert_error_check (jit_module *module, llvm::IRBuilderD& abuilder)
   {
-    return abuilder.CreateLoad (m_lerror_state);
+    llvm::GlobalVariable *globvar = m_lerror_state;
+    if (m_base_jit_module != module)
+      {
+        globvar = module->find_globvar ("error_state");
+
+        if (! globvar)
+          {
+            globvar = module->create_global_variable (m_bool_t, false,
+                                                      "error_state");
+            module->add_global_mapping (globvar, &error_state);
+          }
+
+      }
+    return abuilder.CreateLoad (globvar);
   }
 
   llvm::Value *
-  jit_typeinfo::do_insert_interrupt_check (llvm::IRBuilderD& abuilder)
+  jit_typeinfo::do_insert_interrupt_check (jit_module *module, llvm::IRBuilderD& abuilder)
   {
-    llvm::LoadInst *val = abuilder.CreateLoad (m_loctave_interrupt_state);
+    llvm::GlobalVariable *globvar = m_loctave_interrupt_state;
+    if (m_base_jit_module != module)
+      {
+        globvar = module->find_globvar ("octave_interrupt_state");
+
+        if (! globvar)
+          {
+            globvar = module->create_global_variable (m_sig_atomic_type,
+                                                    false,
+                                                    "octave_interrupt_state");
+            module->add_global_mapping (globvar, &octave_interrupt_state);
+          }
+      }
+    llvm::LoadInst *val = abuilder.CreateLoad (globvar);
     val->setVolatile (true);
     return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0));
   }
@@ -2238,10 +2289,12 @@
         llvm::Value *arg = fn.argument (m_builder, i + 1);
         jit_function agrab = m_grab_fn.overload (args[i]);
         if (agrab.valid ())
-          arg = agrab.call (m_builder, arg);
+          arg = agrab.call (m_base_jit_module, m_builder, arg);
         jit_function acast = do_cast (m_any, args[i]);
         array = m_builder.CreateInsertValue (array,
-                                             acast.call (m_builder, arg), i);
+                                             acast.call (m_base_jit_module,
+                                                         m_builder, arg),
+                                             i);
       }
 
     llvm::Value *array_mem = m_builder.CreateAlloca (array_t);
@@ -2255,11 +2308,12 @@
     llvm::Value *nargin = llvm::ConstantInt::get (intTy, args.size ());
     size_t result_int = reinterpret_cast<size_t> (result);
     llvm::Value *res_llvm = llvm::ConstantInt::get (intTy, result_int);
-    llvm::Value *ret = m_any_call.call (m_builder, fcn, nargin, array,
-                                        res_llvm);
+    llvm::Value *ret = m_any_call.call (m_base_jit_module, m_builder, fcn,
+                                        nargin, array, res_llvm);
 
     jit_function cast_result = do_cast (result, m_any);
-    fn.do_return (m_builder, cast_result.call (m_builder, ret));
+    fn.do_return (m_builder, cast_result.call (m_base_jit_module, m_builder,
+                                               ret));
     paren_subsref_fn.add_overload (fn);
   }
 
@@ -2274,7 +2328,8 @@
 
     llvm::BasicBlock *body = ret.new_block ();
     m_builder.SetInsertPoint (body);
-    llvm::Value *result = fn.call (m_builder, ret.argument (m_builder, 1),
+    llvm::Value *result = fn.call (m_base_jit_module, m_builder,
+                                   ret.argument (m_builder, 1),
                                    ret.argument (m_builder, 0));
     if (ret.result ())
       ret.do_return (m_builder, result);
diff -r e2e895f8a6c2 -r fa22ddcdc796 libinterp/parse-tree/jit-typeinfo.h
--- a/libinterp/parse-tree/jit-typeinfo.h	Thu Jun 27 00:49:30 2019 -0500
+++ b/libinterp/parse-tree/jit-typeinfo.h	Mon Jul 08 11:18:29 2019 -0500
@@ -244,8 +244,8 @@
     // create a function in an invalid state
     jit_function (void);
 
-    jit_function (const jit_module *amodule, jit_convention::type acall_conv,
-                  const llvm::Twine& aname, jit_type *aresult,
+    jit_function (jit_module *amodule, 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
@@ -253,60 +253,63 @@
     jit_function (const jit_function& fn, jit_type *aresult,
                   const std::vector<jit_type *>& aargs);
 
-    jit_function (const jit_function& fn);
+    jit_function (const jit_function& fn) = default;
+
+    jit_function& operator= (const jit_function&) = default;
 
     // erase the interal LLVM function (if it exists).  Will become invalid.
     void erase (void);
 
     bool valid (void) const { return m_llvm_function; }
 
-    std::string name (void) const;
+    constexpr const std::string& name (void) const { return m_name; }
 
     llvm::BasicBlock * new_block (const std::string& aname = "body",
                                   llvm::BasicBlock *insert_before = nullptr);
 
     typedef std::vector<llvm::Value *> arg_vec;
 
-    llvm::Value * call (llvm::IRBuilderD& builder,
+    llvm::Value * call (jit_module *module, llvm::IRBuilderD& builder,
                         const arg_vec& in_args = arg_vec ()) const;
 
-    llvm::Value * call (llvm::IRBuilderD& builder,
+    llvm::Value * call (jit_module *module, llvm::IRBuilderD& builder,
                         const std::vector<jit_value *>& in_args) const;
 
     template <typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, arg_vec& in_args,
-                        llvm::Value * arg1, Args... other_args) const
+    llvm::Value * call (jit_module *module, llvm::IRBuilderD& builder,
+                        arg_vec& in_args, llvm::Value * arg1,
+                        Args... other_args) const
     {
       in_args.push_back (arg1);
-      return call (builder, in_args, other_args...);
+      return call (module, builder, in_args, other_args...);
     }
 
     template <typename T, typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, arg_vec& in_args,
-                        T * arg1, Args... other_args) const
+    llvm::Value * call (jit_module *module, llvm::IRBuilderD& builder,
+                        arg_vec& in_args, T * arg1, Args... other_args) const
     {
       in_args.push_back (arg1->to_llvm ());
-      return call (builder, in_args, other_args...);
+      return call (module, builder, in_args, other_args...);
     }
 
     template <typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, llvm::Value * arg1,
-                        Args... other_args) const
+    llvm::Value * call (jit_module *module, llvm::IRBuilderD& builder,
+                        llvm::Value * arg1, Args... other_args) const
     {
       arg_vec in_args;
       in_args.reserve (1 + sizeof... (other_args));
       in_args.push_back (arg1);
-      return call (builder, in_args, other_args...);
+      return call (module, builder, in_args, other_args...);
     }
 
     template <typename T, typename ...Args>
-    llvm::Value * call (llvm::IRBuilderD& builder, T * arg1,
-                        Args... other_args) const
+    llvm::Value * call (jit_module *module, llvm::IRBuilderD& builder,
+                        T * arg1, Args... other_args) const
     {
       arg_vec in_args;
       in_args.reserve (1 + sizeof... (other_args));
       in_args.push_back (arg1->to_llvm ());
-      return call (builder, in_args, other_args...);
+      return call (module, builder, in_args, other_args...);
     }
 
     llvm::Value * argument (llvm::IRBuilderD& builder, size_t idx) const;
@@ -335,8 +338,10 @@
 
   private:
 
-    const jit_module *m_module;
+    jit_module *m_module;
     llvm::Function *m_llvm_function;
+    llvm::FunctionType *m_llvm_ftype;
+    std::string m_name;
     jit_type *m_result;
     std::vector<jit_type *> m_args;
     jit_convention::type m_call_conv;
@@ -370,43 +375,15 @@
     const jit_function& overload (const signature_vec& types) const;
 
     template <typename ...Args>
-    const jit_function& overload (signature_vec& args, jit_type * arg1,
-                                  Args... other_args) const
+    const jit_function& overload (jit_type *ty, Args... args) const
     {
-      args.push_back (arg1);
-      return overload (args, other_args...);
+      return overload (signature_vec {ty, args...});
     }
 
     template <typename ...Args>
-    const jit_function& overload (jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return overload (args, other_args...);
-    }
-
-    jit_type * result (const signature_vec& types) const
+    jit_type * result (Args... args) const
     {
-      const jit_function& temp = overload (types);
-      return temp.result ();
-    }
-
-    template <typename ...Args>
-    jit_type * result (signature_vec& args, jit_type * arg1,
-                       Args... other_args) const
-    {
-      args.push_back (arg1);
-      return overload (args, other_args...);
-    }
-
-    template <typename ...Args>
-    jit_type * result (jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return overload (args, other_args...);
+      return overload (signature_vec {args...}).result ();
     }
 
     const std::string& name (void) const { return m_name; }
@@ -709,14 +686,16 @@
       return instance ().do_cast (to, from);
     }
 
-    static llvm::Value *insert_error_check (llvm::IRBuilderD& bld)
+    static llvm::Value *insert_error_check (jit_module *module,
+                                            llvm::IRBuilderD& bld)
     {
-      return instance ().do_insert_error_check (bld);
+      return instance ().do_insert_error_check (module, bld);
     }
 
-    static llvm::Value *insert_interrupt_check (llvm::IRBuilderD& bld)
+    static llvm::Value *insert_interrupt_check (jit_module *module,
+                                                llvm::IRBuilderD& bld)
     {
-      return instance ().do_insert_interrupt_check (bld);
+      return instance ().do_insert_interrupt_check (module, bld);
     }
 
     static const jit_operation& end (void)
@@ -798,31 +777,19 @@
     // create a function with an external calling convention
     // forces the function pointer to be specified
     template <typename T>
-    jit_function create_external (T fn, const llvm::Twine& name,
+    jit_function create_external (T fn, const std::string& name,
                                   jit_type * ret, const signature_vec& args
                                   = signature_vec ()) const;
 
     template <typename T, typename ...Args>
-    jit_function create_external (T fn, const llvm::Twine& name,
-                                  jit_type * ret, signature_vec& args,
+    jit_function create_external (T fn, const std::string& name, jit_type *ret,
                                   jit_type * arg1, Args... other_args) const
     {
-      args.push_back (arg1);
-      return create_external (fn, name, ret, args, other_args...);
-    }
-
-    template <typename T, typename ...Args>
-    jit_function create_external (T fn, const llvm::Twine& name, jit_type *ret,
-                                  jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return create_external (fn, name, ret, args, other_args...);
+      return create_external (fn, name, ret, signature_vec {arg1, other_args...});
     }
 
     // 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 (const std::string& name, jit_type *ret,
                                   const signature_vec& args
                                   = signature_vec ()) const
     {
@@ -831,29 +798,17 @@
     }
 
     template <typename ...Args>
-    jit_function create_internal (const llvm::Twine& name, jit_type *ret,
-                                  signature_vec& args,
+    jit_function create_internal (const std::string& name, jit_type *ret,
                                   jit_type * arg1, Args... other_args) const
     {
-      args.push_back (arg1);
-      return create_internal (name, ret, args, other_args...);
-    }
-
-    template <typename ...Args>
-    jit_function create_internal (const llvm::Twine& name, jit_type *ret,
-                                  jit_type * arg1, Args... other_args) const
-    {
-      signature_vec args;
-      args.reserve (1 + sizeof... (other_args));
-      args.push_back (arg1);
-      return create_internal (name, ret, args, other_args...);
+      return create_internal (name, ret, signature_vec {arg1, other_args...});
     }
 
     jit_function create_identity (jit_type *type);
 
-    llvm::Value * do_insert_error_check (llvm::IRBuilderD& bld);
+    llvm::Value * do_insert_error_check (jit_module *module, llvm::IRBuilderD& bld);
 
-    llvm::Value * do_insert_interrupt_check (llvm::IRBuilderD& bld);
+    llvm::Value * do_insert_interrupt_check (jit_module *module, llvm::IRBuilderD& bld);
 
     void add_builtin (const std::string& name);
 
diff -r e2e895f8a6c2 -r fa22ddcdc796 libinterp/parse-tree/pt-jit.cc
--- a/libinterp/parse-tree/pt-jit.cc	Thu Jun 27 00:49:30 2019 -0500
+++ b/libinterp/parse-tree/pt-jit.cc	Mon Jul 08 11:18:29 2019 -0500
@@ -1342,8 +1342,7 @@
 
   // -------------------- jit_convert_llvm --------------------
   llvm::Function *
-  jit_convert_llvm::convert_loop (const jit_module& module,
-                                  const jit_block_list& blocks,
+  jit_convert_llvm::convert_loop (const jit_block_list& blocks,
                                   const std::list<jit_value *>& constants,
                                   const std::string& llvm_function_name)
   {
@@ -1366,7 +1365,7 @@
     ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context),
                                   arg_type->getPointerTo (), false);
 
-    m_function = module.create_llvm_function (ft, llvm_function_name);
+    m_function = m_module->create_llvm_function (ft, llvm_function_name);
     try
       {
         m_prelude = llvm::BasicBlock::Create (context, "prelude", m_function);
@@ -1400,8 +1399,7 @@
   }
 
   jit_function
-  jit_convert_llvm::convert_function (const jit_module& module,
-                                      const jit_block_list& blocks,
+  jit_convert_llvm::convert_function (const jit_block_list& blocks,
                                       const std::list<jit_value *>& constants,
                                       octave_user_function& fcn,
                                       const std::vector<jit_type *>& args)
@@ -1412,7 +1410,7 @@
     jit_return *ret = dynamic_cast<jit_return *> (m_final_block->back ());
     assert (ret);
 
-    m_creating = jit_function (&module, jit_convention::internal,
+    m_creating = jit_function (m_module, jit_convention::internal,
                                "foobar", ret->result_type (), args);
     m_function = m_creating.to_llvm ();
 
@@ -1582,7 +1580,7 @@
     for (size_t i = 0; i < args.size (); ++i)
       args[i] = call.argument (i);
 
-    llvm::Value *ret = ol.call (builder, args);
+    llvm::Value *ret = ol.call (m_module, builder, args);
     call.stash_llvm (ret);
   }
 
@@ -1599,7 +1597,7 @@
         arg = builder.CreateLoad (arg);
 
         const jit_function& ol = extract.overload ();
-        extract.stash_llvm (ol.call (builder, arg));
+        extract.stash_llvm (ol.call (m_module, builder, arg));
       }
   }
 
@@ -1607,7 +1605,7 @@
   jit_convert_llvm::visit (jit_store_argument& store)
   {
     const jit_function& ol = store.overload ();
-    llvm::Value *arg_value = ol.call (builder, store.result ());
+    llvm::Value *arg_value = ol.call (m_module, builder, store.result ());
     llvm::Value *arg = m_arguments[store.name ()];
     store.stash_llvm (builder.CreateStore (arg_value, arg));
   }
@@ -1653,10 +1651,10 @@
     switch (check.check_variable ())
       {
       case jit_error_check::var_error_state:
-        cond = jit_typeinfo::insert_error_check (builder);
+        cond = jit_typeinfo::insert_error_check (m_module, builder);
         break;
       case jit_error_check::var_interrupt:
-        cond = jit_typeinfo::insert_interrupt_check (builder);
+        cond = jit_typeinfo::insert_interrupt_check (m_module, builder);
         break;
       default:
         panic_impossible ();
@@ -1681,7 +1679,7 @@
       {
         const jit_function& ol = jit_typeinfo::get_release (overwrite->type ());
         if (ol.valid ())
-          ol.call (builder, overwrite);
+          ol.call (m_module, builder, overwrite);
       }
   }
 
@@ -1695,7 +1693,7 @@
     const jit_function& ol = me.overload ();
 
     jit_magic_end::context ctx = me.resolve_context ();
-    llvm::Value *ret = ol.call (builder, ctx.m_value, ctx.m_index,
+    llvm::Value *ret = ol.call (m_module, builder, ctx.m_value, ctx.m_index,
                                 ctx.m_count);
     me.stash_llvm (ret);
   }
@@ -2190,32 +2188,20 @@
   void*
   tree_jit::do_getPointerToNamedFunction (const std::string &name) const
   {
-    std::list<jit_module*>::const_iterator it;
-
-    for (it = jm_list.begin (); it != jm_list.end (); it++)
-      {
-        uint64_t addr = (*it)->getFunctionAddress (name);
-
-        if (addr)
-          return reinterpret_cast<void*> (addr);
-      }
-
-    return nullptr;
+    return reinterpret_cast<void*> (do_getSymbolAddress (name));
   }
 
   uint64_t
   tree_jit::do_getSymbolAddress(const std::string &name) const
   {
-    std::list<jit_module*>::const_iterator it;
-
-    for (it = jm_list.begin (); it != jm_list.end (); it++)
+    for (jit_module *module : jm_list)
       {
-        uint64_t addr = (*it)->getFunctionAddress (name);
-
-        if (addr)
-          return addr;
+        // If the module has a definition and addr is not 0 then return.
+        // Note that we are only interested in definitions, not declarations.
+        if (module->contains_llvm_function (name))
+          if (uint64_t addr = module->getFunctionAddress (name))
+            return addr;
       }
-
     return 0;
   }
 
@@ -2388,13 +2374,27 @@
   // Create an LLVM function in the module, with external linkage
   llvm::Function*
   jit_module::create_llvm_function (llvm::FunctionType *ftype,
-                                    const llvm::Twine &name) const
+                                    const std::string& name)
   {
-    // we mark all functinos as external linkage because this prevents
+    // we mark all functions as external linkage because this prevents
     // llvm from getting rid of always inline functions
 
-    return llvm::Function::Create (ftype, llvm::Function::ExternalLinkage,
-                                   name, m_module);
+    llvm::Function *fcn = llvm::Function::Create (ftype,
+                                              llvm::Function::ExternalLinkage,
+                                              name, m_module);
+    m_function_map.emplace (fcn->getName (), fcn);
+    return fcn;
+  }
+
+  llvm::Function *
+  jit_module::create_llvm_function_decl (llvm::FunctionType *ftype,
+                                         const std::string& name)
+  {
+    llvm::Function *fcn = llvm::Function::Create (ftype,
+                                                  llvm::Function::ExternalLinkage,
+                                                  name, m_module);
+    m_function_decl_map.emplace (fcn->getName (), fcn);
+    return fcn;
   }
 
   // Create or insert an LLVM Function declaration for an intrinsic and return
@@ -2410,11 +2410,47 @@
   // Create a global in the module
   llvm::GlobalVariable*
   jit_module::create_global_variable (llvm::Type *type, bool is_constant,
-                                      const llvm::Twine& name) const
+                                      const std::string& name)
+  {
+    llvm::GlobalVariable * globvar = new llvm::GlobalVariable (*m_module,
+                                           type, is_constant,
+                                           llvm::GlobalValue::ExternalLinkage,
+                                           nullptr, name);
+    m_globvar_map.emplace (name, globvar);
+    return globvar;
+  }
+
+  llvm::Function *
+  jit_module::find_llvm_function (const std::string& name) const
   {
-    return new llvm::GlobalVariable (*m_module, type, is_constant,
-                                     llvm::GlobalValue::ExternalLinkage,
-                                     nullptr, name);
+    llvm_function_map::const_iterator it = m_function_map.find (name);
+    if (it != m_function_map.end ())
+      return it->second;
+    return nullptr;
+  }
+
+  llvm::Function *
+  jit_module::find_llvm_function_decl (const std::string& name) const
+  {
+    llvm_function_map::const_iterator it = m_function_decl_map.find (name);
+    if (it != m_function_decl_map.end ())
+      return it->second;
+    return nullptr;
+  }
+
+  llvm::GlobalVariable *
+  jit_module::find_globvar (const std::string& name) const
+  {
+    llvm_globvar_map::const_iterator it = m_globvar_map.find (name);
+    if(it != m_globvar_map.end ())
+      return it->second;
+    return nullptr;
+  }
+
+  std::string
+  jit_module::get_name (void) const
+  {
+    return m_module->getName ();
   }
 
   void
@@ -2551,8 +2587,8 @@
           }
 
         jit_factory& factory = conv.get_factory ();
-        jit_convert_llvm to_llvm;
-        raw_fn = to_llvm.convert_function (*this, infer.get_blocks (),
+        jit_convert_llvm to_llvm (this);
+        raw_fn = to_llvm.convert_function (infer.get_blocks (),
                                            factory.constants (), fcn,
                                            m_argument_types);
 
@@ -2588,16 +2624,16 @@
 
             jit_type *arg_type = m_argument_types[i];
             const jit_function& cast = jit_typeinfo::cast (arg_type, any_t);
-            raw_args[i] = cast.call (builder, arg);
+            raw_args[i] = cast.call (this, builder, arg);
           }
 
-        llvm::Value *result = raw_fn.call (builder, raw_args);
+        llvm::Value *result = raw_fn.call (this, builder, raw_args);
         if (raw_fn.result ())
           {
             jit_type *raw_result_t = raw_fn.result ();
             const jit_function& cast = jit_typeinfo::cast (any_t,
                                                            raw_result_t);
-            result = cast.call (builder, result);
+            result = cast.call (this, builder, result);
           }
         else
           {
@@ -2800,9 +2836,9 @@
           }
 
         jit_factory& factory = conv.get_factory ();
-        jit_convert_llvm to_llvm;
-
-        llvm_function = to_llvm.convert_loop (*this, infer.get_blocks (),
+        jit_convert_llvm to_llvm (this);
+
+        llvm_function = to_llvm.convert_loop (infer.get_blocks (),
                                               factory.constants (),
                                               m_llvm_function_name);
 
diff -r e2e895f8a6c2 -r fa22ddcdc796 libinterp/parse-tree/pt-jit.h
--- a/libinterp/parse-tree/pt-jit.h	Thu Jun 27 00:49:30 2019 -0500
+++ b/libinterp/parse-tree/pt-jit.h	Mon Jul 08 11:18:29 2019 -0500
@@ -29,6 +29,8 @@
 
 #if defined (HAVE_LLVM)
 
+#include <unordered_map>
+
 #include "jit-util.h"
 #include "jit-typeinfo.h"
 #include "jit-ir.h"
@@ -256,13 +258,19 @@
   {
   public:
 
-    llvm::Function * convert_loop (const jit_module& module,
-                                   const jit_block_list& blocks,
+    jit_convert_llvm (jit_module *module)
+      : m_module (module),
+        m_argument_index {},
+        m_arguments {},
+        m_function (nullptr),
+        m_prelude (nullptr)
+    { }
+
+    llvm::Function * convert_loop (const jit_block_list& blocks,
                                    const std::list<jit_value *>& constants,
                                    const std::string& llvm_function_name);
 
-    jit_function convert_function (const jit_module& module,
-                                   const jit_block_list& blocks,
+    jit_function convert_function (const jit_block_list& blocks,
                                    const std::list<jit_value *>& constants,
                                    octave_user_function& fcn,
                                    const std::vector<jit_type *>& args);
@@ -280,6 +288,8 @@
 
   private:
 
+    jit_module *m_module;
+
     // name -> argument index (used for compiling functions)
     std::map<std::string, int> m_argument_index;
 
@@ -535,6 +545,12 @@
 
   public:
 
+    using llvm_function_map = std::unordered_map<std::string,
+                                                 llvm::Function *>;
+
+    using llvm_globvar_map = std::unordered_map<std::string,
+                                                llvm::GlobalVariable *>;
+
     // Create an open module and associated JIT engine
     jit_module (const std::string& module_name
                 = tree_jit::generate_unique_module_name ());
@@ -545,12 +561,16 @@
     // Create an LLVM function in the module, with external linkage
     llvm::Function*
     create_llvm_function (llvm::FunctionType *ftype,
-                          const llvm::Twine &name) const;
+                          const std::string& name);
+
+    llvm::Function*
+    create_llvm_function_decl (llvm::FunctionType *ftype,
+                               const std::string& name);
 
     // Create a global in the module, with external linkage
     llvm::GlobalVariable*
     create_global_variable (llvm::Type *type, bool is_constant,
-                            const llvm::Twine& name) const;
+                             const std::string& name);
 
     // Create or insert an LLVM Function declaration for an intrinsic,
     // and return it
@@ -579,12 +599,40 @@
     // to change anything in the module...
     void finalizeObject (void);
 
+    bool contains_llvm_function (const std::string& name) const
+    {
+      return m_function_map.find (name) != m_function_map.end ();
+    }
+
+    bool contains_llvm_function_decl (const std::string& name) const
+    {
+      return m_function_decl_map.find (name) != m_function_decl_map.end ();
+    }
+
+    bool contains_globvar (const std::string& name) const
+    {
+      return m_globvar_map.find (name) != m_globvar_map.end ();
+    }
+
+    llvm::Function * find_llvm_function (const std::string& name) const;
+
+    llvm::Function * find_llvm_function_decl (const std::string& name) const;
+
+    llvm::GlobalVariable * find_globvar (const std::string& name) const;
+
+    std::string get_name (void) const;
+
   private:
 
     void do_add_global_mapping (const llvm::GlobalValue* gv, void* p) const;
 
     llvm::Module *m_module;
     llvm::ExecutionEngine *m_engine;
+
+    llvm_function_map m_function_decl_map;
+    llvm_function_map m_function_map;
+    llvm_globvar_map m_globvar_map;
+
   };
 
 
