GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
jit-typeinfo.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2012-2015 Max Brister
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // Author: Max Brister <max@2bass.com>
24 
25 // defines required by llvm
26 #define __STDC_LIMIT_MACROS
27 #define __STDC_CONSTANT_MACROS
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 #ifdef HAVE_LLVM
34 
35 #include "jit-typeinfo.h"
36 
37 #ifdef HAVE_LLVM_IR_VERIFIER_H
38 #include <llvm/IR/Verifier.h>
39 #else
40 #include <llvm/Analysis/Verifier.h>
41 #endif
42 
43 #include <llvm/ExecutionEngine/ExecutionEngine.h>
44 
45 #ifdef HAVE_LLVM_IR_FUNCTION_H
46 #include <llvm/IR/GlobalVariable.h>
47 #include <llvm/IR/LLVMContext.h>
48 #include <llvm/IR/Function.h>
49 #include <llvm/IR/Instructions.h>
50 #include <llvm/IR/Intrinsics.h>
51 #else
52 #include <llvm/GlobalVariable.h>
53 #include <llvm/LLVMContext.h>
54 #include <llvm/Function.h>
55 #include <llvm/Instructions.h>
56 #include <llvm/Intrinsics.h>
57 #endif
58 
59 #ifdef HAVE_LLVM_SUPPORT_IRBUILDER_H
60 #include <llvm/Support/IRBuilder.h>
61 #elif defined(HAVE_LLVM_IR_IRBUILDER_H)
62 #include <llvm/IR/IRBuilder.h>
63 #else
64 #include <llvm/IRBuilder.h>
65 #endif
66 
67 #include <llvm/Support/raw_os_ostream.h>
68 
69 #include "jit-ir.h"
70 #include "ov.h"
71 #include "ov-builtin.h"
72 #include "ov-complex.h"
73 #include "ov-scalar.h"
74 #include "pager.h"
75 
76 static llvm::LLVMContext& context = llvm::getGlobalContext ();
77 
79 
80 std::ostream& jit_print (std::ostream& os, jit_type *atype)
81 {
82  if (! atype)
83  return os << "null";
84  return os << atype->name ();
85 }
86 
87 // function that jit code calls
88 extern "C" void
89 octave_jit_print_any (const char *name, octave_base_value *obv)
90 {
91  obv->print_with_name (octave_stdout, name, true);
92 }
93 
94 extern "C" void
95 octave_jit_print_scalar (const char *name, double value)
96 {
97  // FIXME: We should avoid allocating a new octave_scalar each time
98  octave_value ov (value);
99  ov.print_with_name (octave_stdout, name);
100 }
101 
102 extern "C" octave_base_value*
104  octave_base_value *rhs)
105 {
106  octave_value olhs (lhs, true);
107  octave_value orhs (rhs, true);
108  octave_value result = do_binary_op (op, olhs, orhs);
109  octave_base_value *rep = result.internal_rep ();
110  rep->grab ();
111  return rep;
112 }
113 
114 extern "C" octave_idx_type
115 octave_jit_compute_nelem (double base, double limit, double inc)
116 {
117  Range rng = Range (base, limit, inc);
118  return rng.nelem ();
119 }
120 
121 extern "C" void
123 {
124  obv->release ();
125 }
126 
127 extern "C" void
129 {
130  delete m->array;
131 }
132 
133 extern "C" octave_base_value *
135 {
136  obv->grab ();
137  return obv;
138 }
139 
140 extern "C" jit_matrix
142 {
143  return *m->array;
144 }
145 
146 extern "C" octave_base_value *
148 {
149  octave_value ret (*m->array);
150  octave_base_value *rep = ret.internal_rep ();
151  rep->grab ();
152  delete m->array;
153 
154  return rep;
155 }
156 
157 extern "C" jit_matrix
159 {
160  NDArray m = obv->array_value ();
161  obv->release ();
162  return m;
163 }
164 
165 extern "C" octave_base_value *
167 {
168  Range temp (*rng);
169  octave_value ret (temp);
170  octave_base_value *rep = ret.internal_rep ();
171  rep->grab ();
172 
173  return rep;
174 }
175 extern "C" jit_range
177 {
178 
179  jit_range r (obv->range_value ());
180  obv->release ();
181  return r;
182 }
183 
184 extern "C" double
186 {
187  double ret = obv->double_value ();
188  obv->release ();
189  return ret;
190 }
191 
192 extern "C" octave_base_value *
194 {
195  return new octave_scalar (value);
196 }
197 
198 extern "C" Complex
200 {
201  Complex ret = obv->complex_value ();
202  obv->release ();
203  return ret;
204 }
205 
206 extern "C" octave_base_value *
208 {
209  if (c.imag () == 0)
210  return new octave_scalar (c.real ());
211  else
212  return new octave_complex (c);
213 }
214 
215 extern "C" void
217 {
218  try
219  {
221  }
222  catch (const octave_execution_exception&)
223  {
225  }
226 }
227 
228 extern "C" void
230 {
231  try
232  {
234  }
235  catch (const octave_execution_exception&)
236  {
238  }
239 }
240 
241 extern "C" void
243  octave_idx_type ext)
244 {
245  try
246  {
247  gripe_index_out_of_range (nd, dim, iext, ext);
248  }
249  catch (const octave_execution_exception&)
250  {
252  }
253 }
254 
255 extern "C" jit_matrix
257  double value)
258 {
259  NDArray *array = mat->array;
260  if (array->nelem () < index)
261  array->resize1 (index);
262 
263  double *data = array->fortran_vec ();
264  data[index - 1] = value;
265 
266  mat->update ();
267  return *mat;
268 }
269 
270 static void
271 make_indices (double *indices, octave_idx_type idx_count,
272  Array<idx_vector>& result)
273 {
274  result.resize (dim_vector (1, idx_count));
275  for (octave_idx_type i = 0; i < idx_count; ++i)
276  result(i) = idx_vector (indices[i]);
277 }
278 
279 extern "C" double
280 octave_jit_paren_scalar (jit_matrix *mat, double *indicies,
281  octave_idx_type idx_count)
282 {
283  // FIXME: Replace this with a more optimal version
284  try
285  {
286  Array<idx_vector> idx;
287  make_indices (indicies, idx_count, idx);
288 
289  Array<double> ret = mat->array->index (idx);
290  return ret.xelem (0);
291  }
292  catch (const octave_execution_exception&)
293  {
295  return 0;
296  }
297 }
298 
299 extern "C" jit_matrix
301  octave_idx_type idx_count, double value)
302 {
303  // FIXME: Replace this with a more optimal version
304  jit_matrix ret;
305  try
306  {
307  Array<idx_vector> idx;
308  make_indices (indices, idx_count, idx);
309 
310  Matrix temp (1, 1);
311  temp.xelem(0) = value;
312  mat->array->assign (idx, temp);
313  ret.update (mat->array);
314  }
315  catch (const octave_execution_exception&)
316  {
318  }
319 
320  return ret;
321 }
322 
323 extern "C" jit_matrix
325  double value)
326 {
327  NDArray *array = mat->array;
328  bool done = false;
329 
330  // optimize for the simple case (no resizing and no errors)
331  if (*array->jit_ref_count () == 1
332  && index->all_elements_are_ints ())
333  {
334  // this code is similar to idx_vector::fill, but we avoid allocating an
335  // idx_vector and its associated rep
336  octave_idx_type start = static_cast<octave_idx_type> (index->base) - 1;
337  octave_idx_type step = static_cast<octave_idx_type> (index->inc);
338  octave_idx_type nelem = index->nelem;
339  octave_idx_type final = start + nelem * step;
340  if (step < 0)
341  {
342  step = -step;
343  std::swap (final, start);
344  }
345 
346  if (start >= 0 && final < mat->slice_len)
347  {
348  done = true;
349 
350  double *data = array->jit_slice_data ();
351  if (step == 1)
352  std::fill (data + start, data + start + nelem, value);
353  else
354  {
355  for (octave_idx_type i = start; i < final; i += step)
356  data[i] = value;
357  }
358  }
359  }
360 
361  if (! done)
362  {
363  idx_vector idx (*index);
364  NDArray avalue (dim_vector (1, 1));
365  avalue.xelem (0) = value;
366  array->assign (idx, avalue);
367  }
368 
369  jit_matrix ret;
370  ret.update (array);
371  return ret;
372 }
373 
374 extern "C" double
376  octave_idx_type count)
377 {
378  octave_idx_type ndim = mat->dimensions[-1];
379  if (ndim == count)
380  return mat->dimensions[idx];
381  else if (ndim > count)
382  {
383  if (idx == count - 1)
384  {
385  double ret = mat->dimensions[idx];
386  for (octave_idx_type i = idx + 1; i < ndim; ++i)
387  ret *= mat->dimensions[idx];
388  return ret;
389  }
390 
391  return mat->dimensions[idx];
392  }
393  else // ndim < count
394  return idx < ndim ? mat->dimensions[idx] : 1;
395 }
396 
397 extern "C" octave_base_value *
399 {
400  octave_value undef;
401  octave_base_value *ret = undef.internal_rep ();
402  ret->grab ();
403 
404  return ret;
405 }
406 
407 extern "C" Complex
409 {
410  if (lhs.imag () == 0 && rhs.imag() == 0)
411  return Complex (lhs.real () * rhs.real (), 0);
412 
413  return lhs * rhs;
414 }
415 
416 extern "C" Complex
418 {
419  // see src/OPERATORS/op-cs-cs.cc
420  if (rhs == 0.0)
422 
423  return lhs / rhs;
424 }
425 
426 // FIXME: CP form src/xpow.cc
427 static inline int
428 xisint (double x)
429 {
430  return (D_NINT (x) == x
431  && ((x >= 0 && x < std::numeric_limits<int>::max ())
432  || (x <= 0 && x > std::numeric_limits<int>::min ())));
433 }
434 
435 extern "C" Complex
436 octave_jit_pow_scalar_scalar (double lhs, double rhs)
437 {
438  // FIXME: almost CP from src/xpow.cc
439  if (lhs < 0.0 && ! xisint (rhs))
440  return std::pow (Complex (lhs), rhs);
441  return std::pow (lhs, rhs);
442 }
443 
444 extern "C" Complex
446 {
447  if (lhs.imag () == 0 && rhs.imag () == 0)
448  return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ());
449  return std::pow (lhs, rhs);
450 }
451 
452 extern "C" Complex
454 {
455  if (lhs.imag () == 0)
456  return octave_jit_pow_scalar_scalar (lhs.real (), rhs);
457  return std::pow (lhs, rhs);
458 }
459 
460 extern "C" Complex
462 {
463  if (rhs.imag () == 0)
464  return octave_jit_pow_scalar_scalar (lhs, rhs.real ());
465  return std::pow (lhs, rhs);
466 }
467 
468 extern "C" void
470 {
471  std::cout << *m << std::endl;
472 }
473 
474 static void
476 {
477  error ("incorrect type information given to the JIT compiler");
478 }
479 
480 // FIXME: Add support for multiple outputs
481 extern "C" octave_base_value *
483  octave_base_value **argin, jit_type *result_type)
484 {
485  octave_value_list ovl (nargin);
486  for (size_t i = 0; i < nargin; ++i)
487  ovl.xelem (i) = octave_value (argin[i]);
488 
489  ovl = fn (ovl, 1);
490 
491  // FIXME: Check result_type somehow
492  if (result_type)
493  {
494  if (ovl.length () < 1)
495  {
496  gripe_bad_result ();
497  return 0;
498  }
499 
500  octave_value result = ovl.xelem(0);
501  octave_base_value *ret = result.internal_rep ();
502  ret->grab ();
503  return ret;
504  }
505 
506  if (! (ovl.length () == 0
507  || (ovl.length () == 1 && ovl.xelem (0).is_undefined ())))
508  gripe_bad_result ();
509 
510  return 0;
511 }
512 
513 // -------------------- jit_range --------------------
514 bool
516 {
517  Range r (*this);
518  return r.all_elements_are_ints ();
519 }
520 
521 std::ostream&
522 operator<< (std::ostream& os, const jit_range& rng)
523 {
524  return os << "Range[" << rng.base << ", " << rng.limit << ", " << rng.inc
525  << ", " << rng.nelem << "]";
526 }
527 
528 // -------------------- jit_matrix --------------------
529 
530 std::ostream&
531 operator<< (std::ostream& os, const jit_matrix& mat)
532 {
533  return os << "Matrix[" << mat.ref_count << ", " << mat.slice_data << ", "
534  << mat.slice_len << ", " << mat.dimensions << ", "
535  << mat.array << "]";
536 }
537 
538 // -------------------- jit_type --------------------
539 jit_type::jit_type (const std::string& aname, jit_type *aparent,
540  llvm::Type *allvm_type, bool askip_paren, int aid) :
541  mname (aname), mparent (aparent), llvm_type (allvm_type), mid (aid),
542  mdepth (aparent ? aparent->mdepth + 1 : 0), mskip_paren (askip_paren)
543 {
544  std::memset (msret, 0, sizeof (msret));
545  std::memset (mpointer_arg, 0, sizeof (mpointer_arg));
546  std::memset (mpack, 0, sizeof (mpack));
547  std::memset (munpack, 0, sizeof (munpack));
548 
549  for (size_t i = 0; i < jit_convention::length; ++i)
550  mpacked_type[i] = llvm_type;
551 }
552 
553 llvm::Type *
555 {
556  return llvm_type ? llvm_type->getPointerTo () : 0;
557 }
558 
559 // -------------------- jit_function --------------------
560 jit_function::jit_function () : module (0), llvm_function (0), mresult (0),
561  call_conv (jit_convention::length),
562  mcan_error (false)
563 {}
564 
565 jit_function::jit_function (llvm::Module *amodule,
566  jit_convention::type acall_conv,
567  const llvm::Twine& aname, jit_type *aresult,
568  const std::vector<jit_type *>& aargs)
569  : module (amodule), mresult (aresult), args (aargs), call_conv (acall_conv),
570  mcan_error (false)
571 {
572  llvm::SmallVector<llvm::Type *, 15> llvm_args;
573 
574  llvm::Type *rtype = llvm::Type::getVoidTy (context);
575  if (mresult)
576  {
577  rtype = mresult->packed_type (call_conv);
578  if (sret ())
579  {
580  llvm_args.push_back (rtype->getPointerTo ());
581  rtype = llvm::Type::getVoidTy (context);
582  }
583  }
584 
585  for (std::vector<jit_type *>::const_iterator iter = args.begin ();
586  iter != args.end (); ++iter)
587  {
588  jit_type *ty = *iter;
589  assert (ty);
590  llvm::Type *argty = ty->packed_type (call_conv);
591  if (ty->pointer_arg (call_conv))
592  argty = argty->getPointerTo ();
593 
594  llvm_args.push_back (argty);
595  }
596 
597  // we mark all functinos as external linkage because this prevents llvm
598  // from getting rid of always inline functions
599  llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false);
600  llvm_function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage,
601  aname, module);
602 
603  if (sret ())
604  {
605 #ifdef FUNCTION_ADDATTRIBUTE_ARG_IS_ATTRIBUTES
606  llvm::AttrBuilder attr_builder;
607  attr_builder.addAttribute (llvm::Attributes::StructRet);
608  llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
609  llvm_function->addAttribute (1, attrs);
610 #else
611  llvm_function->addAttribute (1, llvm::Attribute::StructRet);
612 #endif
613  }
614 
616 #ifdef FUNCTION_ADDFNATTR_ARG_IS_ATTRIBUTES
617  llvm_function->addFnAttr (llvm::Attributes::AlwaysInline);
618 #else
619  llvm_function->addFnAttr (llvm::Attribute::AlwaysInline);
620 #endif
621 }
622 
624  const std::vector<jit_type *>& aargs)
625  : module (fn.module), llvm_function (fn.llvm_function), mresult (aresult),
626  args (aargs), call_conv (fn.call_conv), mcan_error (fn.mcan_error)
627 {
628 }
629 
631  : module (fn.module), llvm_function (fn.llvm_function), mresult (fn.mresult),
632  args (fn.args), call_conv (fn.call_conv), mcan_error (fn.mcan_error)
633 {}
634 
635 void
637 {
638  if (! llvm_function)
639  return;
640 
641  llvm_function->eraseFromParent ();
642  llvm_function = 0;
643 }
644 
645 std::string
646 jit_function::name (void) const
647 {
648  return llvm_function->getName ();
649 }
650 
651 llvm::BasicBlock *
652 jit_function::new_block (const std::string& aname,
653  llvm::BasicBlock *insert_before)
654 {
655  return llvm::BasicBlock::Create (context, aname, llvm_function,
656  insert_before);
657 }
658 
659 llvm::Value *
661  const std::vector<jit_value *>& in_args) const
662 {
663  if (! valid ())
664  throw jit_fail_exception ("Call not implemented");
665 
666  assert (in_args.size () == args.size ());
667  std::vector<llvm::Value *> llvm_args (args.size ());
668  for (size_t i = 0; i < in_args.size (); ++i)
669  llvm_args[i] = in_args[i]->to_llvm ();
670 
671  return call (builder, llvm_args);
672 }
673 
674 llvm::Value *
676  const std::vector<llvm::Value *>& in_args) const
677 {
678  if (! valid ())
679  throw jit_fail_exception ("Call not implemented");
680 
681  assert (in_args.size () == args.size ());
682  llvm::SmallVector<llvm::Value *, 10> llvm_args;
683  llvm_args.reserve (in_args.size () + sret ());
684 
685  llvm::BasicBlock *insert_block = builder.GetInsertBlock ();
686  llvm::Function *parent = insert_block->getParent ();
687  assert (parent);
688 
689  // we insert allocas inside the prelude block to prevent stack overflows
690  llvm::BasicBlock& prelude = parent->getEntryBlock ();
691  llvm::IRBuilder<> pre_builder (&prelude, prelude.begin ());
692 
693  llvm::AllocaInst *sret_mem = 0;
694  if (sret ())
695  {
696  sret_mem = pre_builder.CreateAlloca (mresult->packed_type (call_conv));
697  llvm_args.push_back (sret_mem);
698  }
699 
700  for (size_t i = 0; i < in_args.size (); ++i)
701  {
702  llvm::Value *arg = in_args[i];
704  if (convert)
705  arg = convert (builder, arg);
706 
707  if (args[i]->pointer_arg (call_conv))
708  {
709  llvm::Type *ty = args[i]->packed_type (call_conv);
710  llvm::Value *alloca = pre_builder.CreateAlloca (ty);
711  builder.CreateStore (arg, alloca);
712  arg = alloca;
713  }
714 
715  llvm_args.push_back (arg);
716  }
717 
718  llvm::CallInst *callinst = builder.CreateCall (llvm_function, llvm_args);
719  llvm::Value *ret = callinst;
720 
721  if (sret ())
722  {
723 #ifdef CALLINST_ADDATTRIBUTE_ARG_IS_ATTRIBUTES
724  llvm::AttrBuilder attr_builder;
725  attr_builder.addAttribute(llvm::Attributes::StructRet);
726  llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
727  callinst->addAttribute (1, attrs);
728 #else
729  callinst->addAttribute (1, llvm::Attribute::StructRet);
730 #endif
731  ret = builder.CreateLoad (sret_mem);
732  }
733 
734  if (mresult)
735  {
737  if (unpack)
738  ret = unpack (builder, ret);
739  }
740 
741  return ret;
742 }
743 
744 llvm::Value *
746 {
747  assert (idx < args.size ());
748 
749  // FIXME: We should be treating arguments like a list, not a vector. Shouldn't
750  // matter much for now, as the number of arguments shouldn't be much bigger
751  // than 4
752  llvm::Function::arg_iterator iter = llvm_function->arg_begin ();
753  if (sret ())
754  ++iter;
755 
756  for (size_t i = 0; i < idx; ++i, ++iter);
757 
758  if (args[idx]->pointer_arg (call_conv))
759  return builder.CreateLoad (iter);
760 
761  return iter;
762 }
763 
764 void
766  bool verify)
767 {
768  assert (! rval == ! mresult);
769 
770  if (rval)
771  {
773  if (convert)
774  rval = convert (builder, rval);
775 
776  if (sret ())
777  {
778  builder.CreateStore (rval, llvm_function->arg_begin ());
779  builder.CreateRetVoid ();
780  }
781  else
782  builder.CreateRet (rval);
783  }
784  else
785  builder.CreateRetVoid ();
786 
787  if (verify)
788  llvm::verifyFunction (*llvm_function);
789 }
790 
791 void
792 jit_function::do_add_mapping (llvm::ExecutionEngine *engine, void *fn)
793 {
794  assert (valid ());
795  engine->addGlobalMapping (llvm_function, fn);
796 }
797 
798 std::ostream&
799 operator<< (std::ostream& os, const jit_function& fn)
800 {
801  llvm::Function *lfn = fn.to_llvm ();
802  os << "jit_function: cc=" << fn.call_conv;
803  llvm::raw_os_ostream llvm_out (os);
804  lfn->print (llvm_out);
805  llvm_out.flush ();
806  return os;
807 }
808 
809 // -------------------- jit_operation --------------------
811 {
812  for (generated_map::iterator iter = generated.begin ();
813  iter != generated.end (); ++iter)
814  {
815  delete iter->first;
816  delete iter->second;
817  }
818 }
819 
820 void
822  const std::vector<jit_type*>& args)
823 {
824  if (args.size () >= overloads.size ())
825  overloads.resize (args.size () + 1);
826 
827  Array<jit_function>& over = overloads[args.size ()];
828  dim_vector dv (over.dims ());
829  Array<octave_idx_type> idx = to_idx (args);
830  bool must_resize = false;
831 
832  if (dv.length () != idx.numel ())
833  {
834  dv.resize (idx.numel ());
835  must_resize = true;
836  }
837 
838  for (octave_idx_type i = 0; i < dv.length (); ++i)
839  if (dv(i) <= idx(i))
840  {
841  must_resize = true;
842  dv(i) = idx(i) + 1;
843  }
844 
845  if (must_resize)
846  over.resize (dv);
847 
848  over(idx) = func;
849 }
850 
851 const jit_function&
852 jit_operation::overload (const std::vector<jit_type*>& types) const
853 {
854  static jit_function null_overload;
855  for (size_t i =0; i < types.size (); ++i)
856  if (! types[i])
857  return null_overload;
858 
859  if (types.size () >= overloads.size ())
860  return do_generate (types);
861 
862  const Array<jit_function>& over = overloads[types.size ()];
863  dim_vector dv (over.dims ());
864  Array<octave_idx_type> idx = to_idx (types);
865  for (octave_idx_type i = 0; i < dv.length (); ++i)
866  if (idx(i) >= dv(i))
867  return do_generate (types);
868 
869  const jit_function& ret = over(idx);
870  if (! ret.valid ())
871  return do_generate (types);
872 
873  return ret;
874 }
875 
877 jit_operation::to_idx (const std::vector<jit_type*>& types) const
878 {
879  octave_idx_type numel = types.size ();
880  numel = std::max (numel, static_cast<octave_idx_type>(2));
881 
882  Array<octave_idx_type> idx (dim_vector (1, numel));
883  for (octave_idx_type i = 0; i < static_cast<octave_idx_type> (types.size ());
884  ++i)
885  idx(i) = types[i]->type_id ();
886 
887  if (types.size () == 0)
888  idx(0) = idx(1) = 0;
889  if (types.size () == 1)
890  {
891  idx(1) = idx(0);
892  idx(0) = 0;
893  }
894 
895  return idx;
896 }
897 
898 const jit_function&
900 {
901  static jit_function null_overload;
902  generated_map::const_iterator find = generated.find (&types);
903  if (find != generated.end ())
904  {
905  if (find->second)
906  return *find->second;
907  else
908  return null_overload;
909  }
910 
911  jit_function *ret = generate (types);
912  generated[new signature_vec (types)] = ret;
913  return ret ? *ret : null_overload;
914 }
915 
916 jit_function *
918 {
919  return 0;
920 }
921 
922 bool
924 ::operator() (const signature_vec *lhs, const signature_vec *rhs) const
925 {
926  const signature_vec& l = *lhs;
927  const signature_vec& r = *rhs;
928 
929  if (l.size () < r.size ())
930  return true;
931  else if (l.size () > r.size ())
932  return false;
933 
934  for (size_t i = 0; i < l.size (); ++i)
935  {
936  if (l[i]->type_id () < r[i]->type_id ())
937  return true;
938  else if (l[i]->type_id () > r[i]->type_id ())
939  return false;
940  }
941 
942  return false;
943 }
944 
945 // -------------------- jit_index_operation --------------------
946 jit_function *
948 {
949  if (types.size () > 2 && types[0] == jit_typeinfo::get_matrix ())
950  {
951  // indexing a matrix with scalars
953  for (size_t i = 1; i < types.size (); ++i)
954  if (types[i] != scalar)
955  return 0;
956 
957  return generate_matrix (types);
958  }
959 
960  return 0;
961 }
962 
963 llvm::Value *
965  const jit_function &fn, size_t start_idx,
966  size_t end_idx) const
967 {
968  size_t n = end_idx - start_idx;
969  llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
970  llvm::ArrayType *array_t = llvm::ArrayType::get (scalar_t, n);
971  llvm::Value *array = llvm::UndefValue::get (array_t);
972  for (size_t i = start_idx; i < end_idx; ++i)
973  {
974  llvm::Value *idx = fn.argument (builder, i);
975  array = builder.CreateInsertValue (array, idx, i - start_idx);
976  }
977 
978  llvm::Value *array_mem = builder.CreateAlloca (array_t);
979  builder.CreateStore (array, array_mem);
980  return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ());
981 }
982 
983 // -------------------- jit_paren_subsref --------------------
984 jit_function *
986 {
987  std::stringstream ss;
988  ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1);
989 
992  ss.str (), scalar, types);
993  fn->mark_can_error ();
994  llvm::BasicBlock *body = fn->new_block ();
995  llvm::IRBuilder<> builder (body);
996 
997  llvm::Value *array = create_arg_array (builder, *fn, 1, types.size ());
998  jit_type *index = jit_typeinfo::get_index ();
999  llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (),
1000  types.size () - 1);
1001  llvm::Value *mat = fn->argument (builder, 0);
1002  llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem);
1003  fn->do_return (builder, ret);
1004  return fn;
1005 }
1006 
1007 void
1009 {
1010  std::vector<jit_type *> types (3);
1011  types[0] = jit_typeinfo::get_matrix ();
1012  types[1] = jit_typeinfo::get_scalar_ptr ();
1013  types[2] = jit_typeinfo::get_index ();
1014 
1017  "octave_jit_paren_scalar", scalar, types);
1020 }
1021 
1022 // -------------------- jit_paren_subsasgn --------------------
1023 jit_function *
1025 {
1026  std::stringstream ss;
1027  ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2);
1028 
1029  jit_type *matrix = jit_typeinfo::get_matrix ();
1031  ss.str (), matrix, types);
1032  fn->mark_can_error ();
1033  llvm::BasicBlock *body = fn->new_block ();
1034  llvm::IRBuilder<> builder (body);
1035 
1036  llvm::Value *array = create_arg_array (builder, *fn, 1, types.size () - 1);
1037  jit_type *index = jit_typeinfo::get_index ();
1038  llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (),
1039  types.size () - 2);
1040 
1041  llvm::Value *mat = fn->argument (builder, 0);
1042  llvm::Value *value = fn->argument (builder, types.size () - 1);
1043  llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem, value);
1044  fn->do_return (builder, ret);
1045  return fn;
1046 }
1047 
1048 void
1050 {
1051  if (paren_scalar.valid ())
1052  return;
1053 
1054  jit_type *matrix = jit_typeinfo::get_matrix ();
1055  std::vector<jit_type *> types (4);
1056  types[0] = matrix;
1057  types[1] = jit_typeinfo::get_scalar_ptr ();
1058  types[2] = jit_typeinfo::get_index ();
1059  types[3] = jit_typeinfo::get_scalar ();
1060 
1062  "octave_jit_paren_scalar", matrix, types);
1065 }
1066 
1067 // -------------------- jit_typeinfo --------------------
1068 void
1069 jit_typeinfo::initialize (llvm::Module *m, llvm::ExecutionEngine *e)
1070 {
1071  new jit_typeinfo (m, e);
1072 }
1073 
1074 // wrap function names to simplify jit_typeinfo::create_external
1075 #define JIT_FN(fn) engine, &fn, #fn
1076 
1077 jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e)
1078  : module (m), engine (e), next_id (0),
1079  builder (*new llvm::IRBuilderD (context))
1080 {
1081  instance = this;
1082 
1083  // FIXME: We should be registering types like in octave_value_typeinfo
1084  llvm::Type *any_t = llvm::StructType::create (context, "octave_base_value");
1085  any_t = any_t->getPointerTo ();
1086 
1087  llvm::Type *scalar_t = llvm::Type::getDoubleTy (context);
1088  llvm::Type *bool_t = llvm::Type::getInt1Ty (context);
1089  llvm::Type *string_t = llvm::Type::getInt8Ty (context);
1090  string_t = string_t->getPointerTo ();
1091  llvm::Type *index_t = llvm::Type::getIntNTy (context,
1092  sizeof(octave_idx_type) * 8);
1093 
1094  llvm::StructType *range_t = llvm::StructType::create (context, "range");
1095  std::vector<llvm::Type *> range_contents (4, scalar_t);
1096  range_contents[3] = index_t;
1097  range_t->setBody (range_contents);
1098 
1099  llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8);
1100 
1101  llvm::StructType *matrix_t = llvm::StructType::create (context, "matrix");
1102  llvm::Type *matrix_contents[5];
1103  matrix_contents[0] = refcount_t->getPointerTo ();
1104  matrix_contents[1] = scalar_t->getPointerTo ();
1105  matrix_contents[2] = index_t;
1106  matrix_contents[3] = index_t->getPointerTo ();
1107  matrix_contents[4] = string_t;
1108  matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5));
1109 
1110  llvm::Type *complex_t = llvm::ArrayType::get (scalar_t, 2);
1111 
1112  // complex_ret is what is passed to C functions in order to get calling
1113  // convention right
1114  llvm::Type *cmplx_inner_cont[] = {scalar_t, scalar_t};
1115  llvm::StructType *cmplx_inner = llvm::StructType::create (cmplx_inner_cont);
1116 
1117  complex_ret = llvm::StructType::create (context, "complex_ret");
1118  {
1119  llvm::Type *contents[] = {cmplx_inner};
1120  complex_ret->setBody (contents);
1121  }
1122 
1123  // create types
1124  any = new_type ("any", 0, any_t);
1125  matrix = new_type ("matrix", any, matrix_t);
1126  complex = new_type ("complex", any, complex_t);
1127  scalar = new_type ("scalar", complex, scalar_t);
1128  scalar_ptr = new_type ("scalar_ptr", 0, scalar_t->getPointerTo ());
1129  any_ptr = new_type ("any_ptr", 0, any_t->getPointerTo ());
1130  range = new_type ("range", any, range_t);
1131  string = new_type ("string", any, string_t);
1132  boolean = new_type ("bool", any, bool_t);
1133  index = new_type ("index", any, index_t);
1134 
1135  create_int (8);
1136  create_int (16);
1137  create_int (32);
1138  create_int (64);
1139 
1140  casts.resize (next_id + 1);
1141  identities.resize (next_id + 1);
1142 
1143  // specify calling conventions
1144  // FIXME: We should detect architecture and do something sane based on that
1145  // here we assume x86 or x86_64
1148 
1149  range->mark_sret (jit_convention::external);
1150  range->mark_pointer_arg (jit_convention::external);
1151 
1155 
1156  if (sizeof (void *) == 4)
1158 
1161 
1162  // bind global variables
1163  lerror_state = new llvm::GlobalVariable (*module, bool_t, false,
1164  llvm::GlobalValue::ExternalLinkage,
1165  0, "error_state");
1166  engine->addGlobalMapping (lerror_state,
1167  reinterpret_cast<void *> (&error_state));
1168 
1169  // sig_atomic_type is going to be some sort of integer
1170  sig_atomic_type = llvm::Type::getIntNTy (context, sizeof(sig_atomic_t) * 8);
1172  = new llvm::GlobalVariable (*module, sig_atomic_type, false,
1173  llvm::GlobalValue::ExternalLinkage, 0,
1174  "octave_interrupt_state");
1175  engine->addGlobalMapping (loctave_interrupt_state,
1176  reinterpret_cast<void *> (&octave_interrupt_state));
1177 
1178  // generic call function
1179  {
1180  jit_type *int_t = intN (sizeof (octave_builtin::fcn) * 8);
1181  any_call = create_external (JIT_FN (octave_jit_call), any, int_t, int_t,
1182  any_ptr, int_t);
1183  }
1184 
1185  // any with anything is an any op
1186  jit_function fn;
1187  jit_type *binary_op_type = intN (sizeof (octave_value::binary_op) * 8);
1188  llvm::Type *llvm_bo_type = binary_op_type->to_llvm ();
1190  any, binary_op_type, any, any);
1191  any_binary.mark_can_error ();
1193  for (size_t i = 0; i < octave_value::num_binary_ops; ++i)
1194  {
1195  octave_value::binary_op op = static_cast<octave_value::binary_op> (i);
1196  std::string op_name = octave_value::binary_op_as_string (op);
1197  binary_ops[i].stash_name ("binary" + op_name);
1198  }
1199 
1201  for (size_t i = 0; i < octave_value::num_unary_ops; ++i)
1202  {
1203  octave_value::unary_op op = static_cast<octave_value::unary_op> (i);
1204  std::string op_name = octave_value::unary_op_as_string (op);
1205  unary_ops[i].stash_name ("unary" + op_name);
1206  }
1207 
1208  for (int op = 0; op < octave_value::num_binary_ops; ++op)
1209  {
1210  llvm::Twine fn_name ("octave_jit_binary_any_any_");
1211  fn_name = fn_name + llvm::Twine (op);
1212 
1213  fn = create_internal (fn_name, any, any, any);
1214  fn.mark_can_error ();
1215  llvm::BasicBlock *block = fn.new_block ();
1216  builder.SetInsertPoint (block);
1217  llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op,
1218  std::numeric_limits<octave_value::binary_op>::is_signed);
1219  llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int);
1220  llvm::Value *ret = any_binary.call (builder, op_as_llvm,
1221  fn.argument (builder, 0),
1222  fn.argument (builder, 1));
1223  fn.do_return (builder, ret);
1224  binary_ops[op].add_overload (fn);
1225  }
1226 
1227  // grab matrix
1229  grab_fn.add_overload (fn);
1230 
1233  grab_fn.add_overload (create_identity (any_ptr));
1234  grab_fn.add_overload (create_identity (boolean));
1237 
1238  // release any
1240  release_fn.add_overload (fn);
1241  release_fn.stash_name ("release");
1242 
1243  // release matrix
1245  release_fn.add_overload (fn);
1246 
1247  // destroy
1249  destroy_fn.stash_name ("destroy");
1254 
1255  // -------------------- scalar related operations --------------------
1256 
1257  // now for binary scalar operations
1258  add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd);
1259  add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub);
1260  add_binary_op (scalar, octave_value::op_mul, llvm::Instruction::FMul);
1261  add_binary_op (scalar, octave_value::op_el_mul, llvm::Instruction::FMul);
1262 
1263  add_binary_fcmp (scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT);
1264  add_binary_fcmp (scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE);
1265  add_binary_fcmp (scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ);
1266  add_binary_fcmp (scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE);
1267  add_binary_fcmp (scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT);
1268  add_binary_fcmp (scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE);
1269 
1271  gripe_div0.mark_can_error ();
1272 
1273  // divide is annoying because it might error
1274  fn = create_internal ("octave_jit_div_scalar_scalar", scalar, scalar, scalar);
1275  fn.mark_can_error ();
1276 
1277  llvm::BasicBlock *body = fn.new_block ();
1278  builder.SetInsertPoint (body);
1279  {
1280  llvm::BasicBlock *warn_block = fn.new_block ("warn");
1281  llvm::BasicBlock *normal_block = fn.new_block ("normal");
1282 
1283  llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
1284  llvm::Value *check = builder.CreateFCmpUEQ (zero, fn.argument (builder, 1));
1285  builder.CreateCondBr (check, warn_block, normal_block);
1286 
1287  builder.SetInsertPoint (warn_block);
1288  gripe_div0.call (builder);
1289  builder.CreateBr (normal_block);
1290 
1291  builder.SetInsertPoint (normal_block);
1292  llvm::Value *ret = builder.CreateFDiv (fn.argument (builder, 0),
1293  fn.argument (builder, 1));
1294  fn.do_return (builder, ret);
1295  }
1296  binary_ops[octave_value::op_div].add_overload (fn);
1297  binary_ops[octave_value::op_el_div].add_overload (fn);
1298 
1299  // ldiv is the same as div with the operators reversed
1300  fn = mirror_binary (fn);
1301  binary_ops[octave_value::op_ldiv].add_overload (fn);
1302  binary_ops[octave_value::op_el_ldiv].add_overload (fn);
1303 
1304  // In general, the result of scalar ^ scalar is a complex number. We might be
1305  // able to improve on this if we keep track of the range of values varaibles
1306  // can take on.
1308  scalar);
1309  binary_ops[octave_value::op_pow].add_overload (fn);
1310  binary_ops[octave_value::op_el_pow].add_overload (fn);
1311 
1312  // now for unary scalar operations
1313  // FIXME: Impelment not
1314  fn = create_internal ("octave_jit_++", scalar, scalar);
1315  body = fn.new_block ();
1316  builder.SetInsertPoint (body);
1317  {
1318  llvm::Value *one = llvm::ConstantFP::get (scalar_t, 1);
1319  llvm::Value *val = fn.argument (builder, 0);
1320  val = builder.CreateFAdd (val, one);
1321  fn.do_return (builder, val);
1322  }
1323  unary_ops[octave_value::op_incr].add_overload (fn);
1324 
1325  fn = create_internal ("octave_jit_--", scalar, scalar);
1326  body = fn.new_block ();
1327  builder.SetInsertPoint (body);
1328  {
1329  llvm::Value *one = llvm::ConstantFP::get (scalar_t, 1);
1330  llvm::Value *val = fn.argument (builder, 0);
1331  val = builder.CreateFSub (val, one);
1332  fn.do_return (builder, val);
1333  }
1334  unary_ops[octave_value::op_decr].add_overload (fn);
1335 
1336  fn = create_internal ("octave_jit_uminus", scalar, scalar);
1337  body = fn.new_block ();
1338  builder.SetInsertPoint (body);
1339  {
1340  llvm::Value *mone = llvm::ConstantFP::get (scalar_t, -1);
1341  llvm::Value *val = fn.argument (builder, 0);
1342  val = builder.CreateFMul (val, mone);
1343  fn.do_return (builder, val);
1344  }
1345  unary_ops[octave_value::op_uminus].add_overload (fn);
1346 
1347  fn = create_identity (scalar);
1348  unary_ops[octave_value::op_uplus].add_overload (fn);
1349  unary_ops[octave_value::op_transpose].add_overload (fn);
1350  unary_ops[octave_value::op_hermitian].add_overload (fn);
1351 
1352  // now for binary complex operations
1353  fn = create_internal ("octave_jit_+_complex_complex", complex, complex,
1354  complex);
1355  body = fn.new_block ();
1356  builder.SetInsertPoint (body);
1357  {
1358  llvm::Value *lhs = fn.argument (builder, 0);
1359  llvm::Value *rhs = fn.argument (builder, 1);
1360  llvm::Value *real = builder.CreateFAdd (complex_real (lhs),
1361  complex_real (rhs));
1362  llvm::Value *imag = builder.CreateFAdd (complex_imag (lhs),
1363  complex_imag (rhs));
1364  fn.do_return (builder, complex_new (real, imag));
1365  }
1366  binary_ops[octave_value::op_add].add_overload (fn);
1367 
1368  fn = create_internal ("octave_jit_-_complex_complex", complex, complex,
1369  complex);
1370  body = fn.new_block ();
1371  builder.SetInsertPoint (body);
1372  {
1373  llvm::Value *lhs = fn.argument (builder, 0);
1374  llvm::Value *rhs = fn.argument (builder, 1);
1375  llvm::Value *real = builder.CreateFSub (complex_real (lhs),
1376  complex_real (rhs));
1377  llvm::Value *imag = builder.CreateFSub (complex_imag (lhs),
1378  complex_imag (rhs));
1379  fn.do_return (builder, complex_new (real, imag));
1380  }
1381  binary_ops[octave_value::op_sub].add_overload (fn);
1382 
1384  complex, complex, complex);
1385  binary_ops[octave_value::op_mul].add_overload (fn);
1386  binary_ops[octave_value::op_el_mul].add_overload (fn);
1387 
1389  complex, complex, complex);
1390  complex_div.mark_can_error ();
1391  binary_ops[octave_value::op_div].add_overload (fn);
1392  binary_ops[octave_value::op_ldiv].add_overload (fn);
1393 
1395  complex, complex);
1396  binary_ops[octave_value::op_pow].add_overload (fn);
1397  binary_ops[octave_value::op_el_pow].add_overload (fn);
1398 
1399  fn = create_internal ("octave_jit_*_scalar_complex", complex, scalar,
1400  complex);
1401  jit_function mul_scalar_complex = fn;
1402  body = fn.new_block ();
1403  builder.SetInsertPoint (body);
1404  {
1405  llvm::BasicBlock *complex_mul = fn.new_block ("complex_mul");
1406  llvm::BasicBlock *scalar_mul = fn.new_block ("scalar_mul");
1407 
1408  llvm::Value *fzero = llvm::ConstantFP::get (scalar_t, 0);
1409  llvm::Value *lhs = fn.argument (builder, 0);
1410  llvm::Value *rhs = fn.argument (builder, 1);
1411 
1412  llvm::Value *cmp = builder.CreateFCmpUEQ (complex_imag (rhs), fzero);
1413  builder.CreateCondBr (cmp, scalar_mul, complex_mul);
1414 
1415  builder.SetInsertPoint (scalar_mul);
1416  llvm::Value *temp = complex_real (rhs);
1417  temp = builder.CreateFMul (lhs, temp);
1418  fn.do_return (builder, complex_new (temp, fzero), false);
1419 
1420 
1421  builder.SetInsertPoint (complex_mul);
1422  temp = complex_new (builder.CreateFMul (lhs, complex_real (rhs)),
1423  builder.CreateFMul (lhs, complex_imag (rhs)));
1424  fn.do_return (builder, temp);
1425  }
1426  binary_ops[octave_value::op_mul].add_overload (fn);
1427  binary_ops[octave_value::op_el_mul].add_overload (fn);
1428 
1429 
1430  fn = mirror_binary (mul_scalar_complex);
1431  binary_ops[octave_value::op_mul].add_overload (fn);
1432  binary_ops[octave_value::op_el_mul].add_overload (fn);
1433 
1434  fn = create_internal ("octave_jit_+_scalar_complex", complex, scalar,
1435  complex);
1436  body = fn.new_block ();
1437  builder.SetInsertPoint (body);
1438  {
1439  llvm::Value *lhs = fn.argument (builder, 0);
1440  llvm::Value *rhs = fn.argument (builder, 1);
1441  llvm::Value *real = builder.CreateFAdd (lhs, complex_real (rhs));
1442  fn.do_return (builder, complex_real (rhs, real));
1443  }
1444  binary_ops[octave_value::op_add].add_overload (fn);
1445 
1446  fn = mirror_binary (fn);
1447  binary_ops[octave_value::op_add].add_overload (fn);
1448 
1449  fn = create_internal ("octave_jit_-_complex_scalar", complex, complex,
1450  scalar);
1451  body = fn.new_block ();
1452  builder.SetInsertPoint (body);
1453  {
1454  llvm::Value *lhs = fn.argument (builder, 0);
1455  llvm::Value *rhs = fn.argument (builder, 1);
1456  llvm::Value *real = builder.CreateFSub (complex_real (lhs), rhs);
1457  fn.do_return (builder, complex_real (lhs, real));
1458  }
1459  binary_ops[octave_value::op_sub].add_overload (fn);
1460 
1461  fn = create_internal ("octave_jit_-_scalar_complex", complex, scalar,
1462  complex);
1463  body = fn.new_block ();
1464  builder.SetInsertPoint (body);
1465  {
1466  llvm::Value *lhs = fn.argument (builder, 0);
1467  llvm::Value *rhs = fn.argument (builder, 1);
1468  llvm::Value *real = builder.CreateFSub (lhs, complex_real (rhs));
1469  fn.do_return (builder, complex_real (rhs, real));
1470  }
1471  binary_ops[octave_value::op_sub].add_overload (fn);
1472 
1474  complex);
1475  binary_ops[octave_value::op_pow].add_overload (fn);
1476  binary_ops[octave_value::op_el_pow].add_overload (fn);
1477 
1479  complex, scalar);
1480  binary_ops[octave_value::op_pow].add_overload (fn);
1481  binary_ops[octave_value::op_el_pow].add_overload (fn);
1482 
1483  // now for binary index operators
1484  add_binary_op (index, octave_value::op_add, llvm::Instruction::Add);
1485 
1486  // and binary bool operators
1487  add_binary_op (boolean, octave_value::op_el_or, llvm::Instruction::Or);
1488  add_binary_op (boolean, octave_value::op_el_and, llvm::Instruction::And);
1489 
1490  // now for printing functions
1491  print_fn.stash_name ("print");
1492  add_print (any, reinterpret_cast<void *> (&octave_jit_print_any));
1493  add_print (scalar, reinterpret_cast<void *> (&octave_jit_print_scalar));
1494 
1495  // initialize for loop
1496  for_init_fn.stash_name ("for_init");
1497 
1498  fn = create_internal ("octave_jit_for_range_init", index, range);
1499  body = fn.new_block ();
1500  builder.SetInsertPoint (body);
1501  {
1502  llvm::Value *zero = llvm::ConstantInt::get (index_t, 0);
1503  fn.do_return (builder, zero);
1504  }
1506 
1507  // bounds check for for loop
1508  for_check_fn.stash_name ("for_check");
1509 
1510  fn = create_internal ("octave_jit_for_range_check", boolean, range, index);
1511  body = fn.new_block ();
1512  builder.SetInsertPoint (body);
1513  {
1514  llvm::Value *nelem
1515  = builder.CreateExtractValue (fn.argument (builder, 0), 3);
1516  llvm::Value *idx = fn.argument (builder, 1);
1517  llvm::Value *ret = builder.CreateICmpULT (idx, nelem);
1518  fn.do_return (builder, ret);
1519  }
1521 
1522  // index variabe for for loop
1523  for_index_fn.stash_name ("for_index");
1524 
1525  fn = create_internal ("octave_jit_for_range_idx", scalar, range, index);
1526  body = fn.new_block ();
1527  builder.SetInsertPoint (body);
1528  {
1529  llvm::Value *idx = fn.argument (builder, 1);
1530  llvm::Value *didx = builder.CreateSIToFP (idx, scalar_t);
1531  llvm::Value *rng = fn.argument (builder, 0);
1532  llvm::Value *base = builder.CreateExtractValue (rng, 0);
1533  llvm::Value *inc = builder.CreateExtractValue (rng, 2);
1534 
1535  llvm::Value *ret = builder.CreateFMul (didx, inc);
1536  ret = builder.CreateFAdd (base, ret);
1537  fn.do_return (builder, ret);
1538  }
1540 
1541  // logically true
1542  logically_true_fn.stash_name ("logically_true");
1543 
1544  jit_function gripe_nantl
1546  gripe_nantl.mark_can_error ();
1547 
1548  fn = create_internal ("octave_jit_logically_true_scalar", boolean, scalar);
1549  fn.mark_can_error ();
1550 
1551  body = fn.new_block ();
1552  builder.SetInsertPoint (body);
1553  {
1554  llvm::BasicBlock *error_block = fn.new_block ("error");
1555  llvm::BasicBlock *normal_block = fn.new_block ("normal");
1556 
1557  llvm::Value *check = builder.CreateFCmpUNE (fn.argument (builder, 0),
1558  fn.argument (builder, 0));
1559  builder.CreateCondBr (check, error_block, normal_block);
1560 
1561  builder.SetInsertPoint (error_block);
1562  gripe_nantl.call (builder);
1563  builder.CreateBr (normal_block);
1564  builder.SetInsertPoint (normal_block);
1565 
1566  llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
1567  llvm::Value *ret = builder.CreateFCmpONE (fn.argument (builder, 0), zero);
1568  fn.do_return (builder, ret);
1569  }
1571 
1572  // logically_true boolean
1573  fn = create_identity (boolean);
1575 
1576  // make_range
1577  // FIXME: May be benificial to implement all in LLVM
1578  make_range_fn.stash_name ("make_range");
1579  jit_function compute_nelem
1581  index, scalar, scalar, scalar);
1582 
1583 
1584  fn = create_internal ("octave_jit_make_range", range, scalar, scalar, scalar);
1585  body = fn.new_block ();
1586  builder.SetInsertPoint (body);
1587  {
1588  llvm::Value *base = fn.argument (builder, 0);
1589  llvm::Value *limit = fn.argument (builder, 1);
1590  llvm::Value *inc = fn.argument (builder, 2);
1591  llvm::Value *nelem = compute_nelem.call (builder, base, limit, inc);
1592 
1593  llvm::Value *dzero = llvm::ConstantFP::get (scalar_t, 0);
1594  llvm::Value *izero = llvm::ConstantInt::get (index_t, 0);
1595  llvm::Value *rng = llvm::ConstantStruct::get (range_t, dzero, dzero, dzero,
1596  izero, NULL);
1597  rng = builder.CreateInsertValue (rng, base, 0);
1598  rng = builder.CreateInsertValue (rng, limit, 1);
1599  rng = builder.CreateInsertValue (rng, inc, 2);
1600  rng = builder.CreateInsertValue (rng, nelem, 3);
1601  fn.do_return (builder, rng);
1602  }
1604 
1605  // paren_subsref
1606  jit_type *jit_int = intN (sizeof (int) * 8);
1607  llvm::Type *int_t = jit_int->to_llvm ();
1608  jit_function ginvalid_index
1611  0, jit_int, jit_int, index,
1612  index);
1613 
1614  fn = create_internal ("()subsref", scalar, matrix, scalar);
1615  fn.mark_can_error ();
1616 
1617  body = fn.new_block ();
1618  builder.SetInsertPoint (body);
1619  {
1620  llvm::Value *one_idx = llvm::ConstantInt::get (index_t, 1);
1621  llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
1622 
1623  llvm::Value *undef = llvm::UndefValue::get (scalar_t);
1624  llvm::Value *mat = fn.argument (builder, 0);
1625  llvm::Value *idx = fn.argument (builder, 1);
1626 
1627  // convert index to scalar to integer, and check index >= 1
1628  llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t);
1629  llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t);
1630  llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx);
1631  llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one_idx);
1632  llvm::Value *cond = builder.CreateOr (cond0, cond1);
1633 
1634  llvm::BasicBlock *done = fn.new_block ("done");
1635  llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
1636  llvm::BasicBlock *normal = fn.new_block ("normal", done);
1637  builder.CreateCondBr (cond, conv_error, normal);
1638 
1639  builder.SetInsertPoint (conv_error);
1640  ginvalid_index.call (builder);
1641  builder.CreateBr (done);
1642 
1643  builder.SetInsertPoint (normal);
1644  llvm::Value *len
1645  = builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (2));
1646  cond = builder.CreateICmpSGT (int_idx, len);
1647 
1648 
1649  llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
1650  llvm::BasicBlock *success = fn.new_block ("success", done);
1651  builder.CreateCondBr (cond, bounds_error, success);
1652 
1653  builder.SetInsertPoint (bounds_error);
1654  gindex_range.call (builder, one_int, one_int, int_idx, len);
1655  builder.CreateBr (done);
1656 
1657  builder.SetInsertPoint (success);
1658  llvm::Value *data = builder.CreateExtractValue (mat,
1659  llvm::ArrayRef<unsigned> (1));
1660  llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx);
1661  llvm::Value *ret = builder.CreateLoad (gep);
1662  builder.CreateBr (done);
1663 
1664  builder.SetInsertPoint (done);
1665 
1666  llvm::PHINode *merge = llvm::PHINode::Create (scalar_t, 3);
1667  builder.Insert (merge);
1668  merge->addIncoming (undef, conv_error);
1669  merge->addIncoming (undef, bounds_error);
1670  merge->addIncoming (ret, success);
1671  fn.do_return (builder, merge);
1672  }
1674 
1675  // paren subsasgn
1676  paren_subsasgn_fn.stash_name ("()subsasgn");
1677 
1678  jit_function resize_paren_subsasgn
1680  index, scalar);
1681 
1682  fn = create_internal ("octave_jit_paren_subsasgn", matrix, matrix, scalar,
1683  scalar);
1684  fn.mark_can_error ();
1685  body = fn.new_block ();
1686  builder.SetInsertPoint (body);
1687  {
1688  llvm::Value *one_idx = llvm::ConstantInt::get (index_t, 1);
1689  llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
1690 
1691  llvm::Value *mat = fn.argument (builder, 0);
1692  llvm::Value *idx = fn.argument (builder, 1);
1693  llvm::Value *value = fn.argument (builder, 2);
1694 
1695  llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t);
1696  llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t);
1697  llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx);
1698  llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one_idx);
1699  llvm::Value *cond = builder.CreateOr (cond0, cond1);
1700 
1701  llvm::BasicBlock *done = fn.new_block ("done");
1702 
1703  llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
1704  llvm::BasicBlock *normal = fn.new_block ("normal", done);
1705  builder.CreateCondBr (cond, conv_error, normal);
1706  builder.SetInsertPoint (conv_error);
1707  ginvalid_index.call (builder);
1708  builder.CreateBr (done);
1709 
1710  builder.SetInsertPoint (normal);
1711  llvm::Value *len = builder.CreateExtractValue (mat, 2);
1712  cond0 = builder.CreateICmpSGT (int_idx, len);
1713 
1714  llvm::Value *rcount = builder.CreateExtractValue (mat, 0);
1715  rcount = builder.CreateLoad (rcount);
1716  cond1 = builder.CreateICmpSGT (rcount, one_int);
1717  cond = builder.CreateOr (cond0, cond1);
1718 
1719  llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
1720  llvm::BasicBlock *success = fn.new_block ("success", done);
1721  builder.CreateCondBr (cond, bounds_error, success);
1722 
1723  // resize on out of bounds access
1724  builder.SetInsertPoint (bounds_error);
1725  llvm::Value *resize_result = resize_paren_subsasgn.call (builder, mat,
1726  int_idx, value);
1727  builder.CreateBr (done);
1728 
1729  builder.SetInsertPoint (success);
1730  llvm::Value *data
1731  = builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (1));
1732  llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx);
1733  builder.CreateStore (value, gep);
1734  builder.CreateBr (done);
1735 
1736  builder.SetInsertPoint (done);
1737 
1738  llvm::PHINode *merge = llvm::PHINode::Create (matrix_t, 3);
1739  builder.Insert (merge);
1740  merge->addIncoming (mat, conv_error);
1741  merge->addIncoming (resize_result, bounds_error);
1742  merge->addIncoming (mat, success);
1743  fn.do_return (builder, merge);
1744  }
1746 
1748  matrix, range, scalar);
1749  fn.mark_can_error ();
1751 
1752  end1_fn.stash_name ("end1");
1753  fn = create_internal ("octave_jit_end1_matrix", scalar, matrix, index, index);
1754  body = fn.new_block ();
1755  builder.SetInsertPoint (body);
1756  {
1757  llvm::Value *mat = fn.argument (builder, 0);
1758  llvm::Value *ret = builder.CreateExtractValue (mat, 2);
1759  fn.do_return (builder, builder.CreateSIToFP (ret, scalar_t));
1760  }
1761  end1_fn.add_overload (fn);
1762 
1763  end_fn.stash_name ("end");
1765  index);
1766  end_fn.add_overload (fn);
1767 
1768  // -------------------- create_undef --------------------
1769  create_undef_fn.stash_name ("create_undef");
1772 
1773  casts[any->type_id ()].stash_name ("(any)");
1774  casts[scalar->type_id ()].stash_name ("(scalar)");
1775  casts[complex->type_id ()].stash_name ("(complex)");
1776  casts[matrix->type_id ()].stash_name ("(matrix)");
1777  casts[range->type_id ()].stash_name ("(range)");
1778 
1779  // cast any <- matrix
1781  casts[any->type_id ()].add_overload (fn);
1782 
1783  // cast matrix <- any
1785  casts[matrix->type_id ()].add_overload (fn);
1786 
1787  // cast any <- range
1789  casts[any->type_id ()].add_overload (fn);
1790 
1791  // cast range <- any
1793  casts[range->type_id ()].add_overload (fn);
1794 
1795  // cast any <- scalar
1797  casts[any->type_id ()].add_overload (fn);
1798 
1799  // cast scalar <- any
1801  casts[scalar->type_id ()].add_overload (fn);
1802 
1803  // cast any <- complex
1805  casts[any->type_id ()].add_overload (fn);
1806 
1807  // cast complex <- any
1809  casts[complex->type_id ()].add_overload (fn);
1810 
1811  // cast complex <- scalar
1812  fn = create_internal ("octave_jit_cast_complex_scalar", complex, scalar);
1813  body = fn.new_block ();
1814  builder.SetInsertPoint (body);
1815  {
1816  llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
1817  fn.do_return (builder, complex_new (fn.argument (builder, 0), zero));
1818  }
1819  casts[complex->type_id ()].add_overload (fn);
1820 
1821  // cast scalar <- complex
1822  fn = create_internal ("octave_jit_cast_scalar_complex", scalar, complex);
1823  body = fn.new_block ();
1824  builder.SetInsertPoint (body);
1825  fn.do_return (builder, complex_real (fn.argument (builder, 0)));
1826  casts[scalar->type_id ()].add_overload (fn);
1827 
1828  // cast any <- any
1829  fn = create_identity (any);
1830  casts[any->type_id ()].add_overload (fn);
1831 
1832  // cast scalar <- scalar
1833  fn = create_identity (scalar);
1834  casts[scalar->type_id ()].add_overload (fn);
1835 
1836  // cast complex <- complex
1837  fn = create_identity (complex);
1838  casts[complex->type_id ()].add_overload (fn);
1839 
1840  // -------------------- builtin functions --------------------
1841  add_builtin ("#unknown_function");
1842  unknown_function = builtins["#unknown_function"];
1843 
1844  add_builtin ("sin");
1845  register_intrinsic ("sin", llvm::Intrinsic::sin, scalar, scalar);
1846  register_generic ("sin", matrix, matrix);
1847 
1848  add_builtin ("cos");
1849  register_intrinsic ("cos", llvm::Intrinsic::cos, scalar, scalar);
1850  register_generic ("cos", matrix, matrix);
1851 
1852  add_builtin ("exp");
1853  register_intrinsic ("exp", llvm::Intrinsic::exp, scalar, scalar);
1854  register_generic ("exp", matrix, matrix);
1855 
1856  add_builtin ("balance");
1857  register_generic ("balance", matrix, matrix);
1858 
1859  add_builtin ("cond");
1860  register_generic ("cond", scalar, matrix);
1861 
1862  add_builtin ("det");
1863  register_generic ("det", scalar, matrix);
1864 
1865  add_builtin ("norm");
1866  register_generic ("norm", scalar, matrix);
1867 
1868  add_builtin ("rand");
1869  register_generic ("rand", matrix, scalar);
1870  register_generic ("rand", matrix, std::vector<jit_type *> (2, scalar));
1871 
1872  add_builtin ("magic");
1873  register_generic ("magic", matrix, scalar);
1874  register_generic ("magic", matrix, std::vector<jit_type *> (2, scalar));
1875 
1876  add_builtin ("eye");
1877  register_generic ("eye", matrix, scalar);
1878  register_generic ("eye", matrix, std::vector<jit_type *> (2, scalar));
1879 
1880  add_builtin ("mod");
1881  register_generic ("mod", scalar, std::vector<jit_type *> (2, scalar));
1882 
1883  casts.resize (next_id + 1);
1884  jit_function any_id = create_identity (any);
1886  any, any);
1887  jit_function release_any = get_release (any);
1888  std::vector<jit_type *> args;
1889  args.resize (1);
1890 
1891  for (std::map<std::string, jit_type *>::iterator iter = builtins.begin ();
1892  iter != builtins.end (); ++iter)
1893  {
1894  jit_type *btype = iter->second;
1895  args[0] = btype;
1896 
1897  grab_fn.add_overload (jit_function (grab_any, btype, args));
1898  release_fn.add_overload (jit_function (release_any, 0, args));
1899  casts[any->type_id ()].add_overload (jit_function (any_id, any, args));
1900 
1901  args[0] = any;
1902  casts[btype->type_id ()].add_overload (jit_function (any_id, btype,
1903  args));
1904  }
1905 }
1906 
1907 const jit_function&
1909 {
1910  jit_const_index *ccount = dynamic_cast<jit_const_index *> (count);
1911  if (ccount && ccount->value () == 1)
1912  return end1_fn.overload (value->type (), idx->type (), count->type ());
1913 
1914  return end_fn.overload (value->type (), idx->type (), count->type ());
1915 }
1916 
1917 jit_type*
1918 jit_typeinfo::new_type (const std::string& name, jit_type *parent,
1919  llvm::Type *llvm_type, bool skip_paren)
1920 {
1921  jit_type *ret = new jit_type (name, parent, llvm_type, skip_paren, next_id++);
1922  id_to_type.push_back (ret);
1923  return ret;
1924 }
1925 
1926 void
1928 {
1929  std::stringstream name;
1930  name << "octave_jit_print_" << ty->name ();
1931  jit_function fn = create_external (engine, fptr, name.str (),
1932  0, intN (8), ty);
1933  print_fn.add_overload (fn);
1934 }
1935 
1936 // FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp
1937 void
1938 jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op)
1939 {
1940  std::stringstream fname;
1941  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
1942  fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op)
1943  << "_" << ty->name ();
1944 
1945  jit_function fn = create_internal (fname.str (), ty, ty, ty);
1946  llvm::BasicBlock *block = fn.new_block ();
1947  builder.SetInsertPoint (block);
1948  llvm::Instruction::BinaryOps temp
1949  = static_cast<llvm::Instruction::BinaryOps>(llvm_op);
1950 
1951  llvm::Value *ret = builder.CreateBinOp (temp, fn.argument (builder, 0),
1952  fn.argument (builder, 1));
1953  fn.do_return (builder, ret);
1954  binary_ops[op].add_overload (fn);
1955 }
1956 
1957 void
1959 {
1960  std::stringstream fname;
1961  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
1962  fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
1963  << "_" << ty->name ();
1964 
1965  jit_function fn = create_internal (fname.str (), boolean, ty, ty);
1966  llvm::BasicBlock *block = fn.new_block ();
1967  builder.SetInsertPoint (block);
1968  llvm::CmpInst::Predicate temp
1969  = static_cast<llvm::CmpInst::Predicate>(llvm_op);
1970  llvm::Value *ret = builder.CreateICmp (temp, fn.argument (builder, 0),
1971  fn.argument (builder, 1));
1972  fn.do_return (builder, ret);
1973  binary_ops[op].add_overload (fn);
1974 }
1975 
1976 void
1978 {
1979  std::stringstream fname;
1980  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
1981  fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
1982  << "_" << ty->name ();
1983 
1984  jit_function fn = create_internal (fname.str (), boolean, ty, ty);
1985  llvm::BasicBlock *block = fn.new_block ();
1986  builder.SetInsertPoint (block);
1987  llvm::CmpInst::Predicate temp
1988  = static_cast<llvm::CmpInst::Predicate>(llvm_op);
1989  llvm::Value *ret = builder.CreateFCmp (temp, fn.argument (builder, 0),
1990  fn.argument (builder, 1));
1991  fn.do_return (builder, ret);
1992  binary_ops[op].add_overload (fn);
1993 }
1994 
1997  jit_type *ret,
1998  const std::vector<jit_type *>& args)
1999 {
2000  jit_function result (module, cc, name, ret, args);
2001  return result;
2002 }
2003 
2006 {
2007  size_t id = type->type_id ();
2008  if (id >= identities.size ())
2009  identities.resize (id + 1);
2010 
2011  if (! identities[id].valid ())
2012  {
2013  std::stringstream name;
2014  name << "id_" << type->name ();
2015 
2016  jit_function fn = create_internal (name.str (), type, type);
2017  llvm::BasicBlock *body = fn.new_block ();
2018  builder.SetInsertPoint (body);
2019  fn.do_return (builder, fn.argument (builder, 0));
2020  return identities[id] = fn;
2021  }
2022 
2023  return identities[id];
2024 }
2025 
2026 llvm::Value *
2028 {
2029  return abuilder.CreateLoad (lerror_state);
2030 }
2031 
2032 llvm::Value *
2034 {
2035  llvm::LoadInst *val = abuilder.CreateLoad (loctave_interrupt_state);
2036  val->setVolatile (true);
2037  return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0));
2038 }
2039 
2040 void
2041 jit_typeinfo::add_builtin (const std::string& name)
2042 {
2043  jit_type *btype = new_type (name, any, any->to_llvm (), true);
2044  builtins[name] = btype;
2045 
2046  octave_builtin *ov_builtin = find_builtin (name);
2047  if (ov_builtin)
2048  ov_builtin->stash_jit (*btype);
2049 }
2050 
2051 void
2052 jit_typeinfo::register_intrinsic (const std::string& name, size_t iid,
2053  jit_type *result,
2054  const std::vector<jit_type *>& args)
2055 {
2056  jit_type *builtin_type = builtins[name];
2057  size_t nargs = args.size ();
2058  llvm::SmallVector<llvm::Type *, 5> llvm_args (nargs);
2059  for (size_t i = 0; i < nargs; ++i)
2060  llvm_args[i] = args[i]->to_llvm ();
2061 
2062  llvm::Intrinsic::ID id = static_cast<llvm::Intrinsic::ID> (iid);
2063  llvm::Function *ifun = llvm::Intrinsic::getDeclaration (module, id,
2064  llvm_args);
2065  std::stringstream fn_name;
2066  fn_name << "octave_jit_" << name;
2067 
2068  std::vector<jit_type *> args1 (nargs + 1);
2069  args1[0] = builtin_type;
2070  std::copy (args.begin (), args.end (), args1.begin () + 1);
2071 
2072  // The first argument will be the Octave function, but we already know that
2073  // the function call is the equivalent of the intrinsic, so we ignore it and
2074  // call the intrinsic with the remaining arguments.
2075  jit_function fn = create_internal (fn_name.str (), result, args1);
2076  llvm::BasicBlock *body = fn.new_block ();
2077  builder.SetInsertPoint (body);
2078 
2079  llvm::SmallVector<llvm::Value *, 5> fargs (nargs);
2080  for (size_t i = 0; i < nargs; ++i)
2081  fargs[i] = fn.argument (builder, i + 1);
2082 
2083  llvm::Value *ret = builder.CreateCall (ifun, fargs);
2084  fn.do_return (builder, ret);
2086 }
2087 
2089 jit_typeinfo::find_builtin (const std::string& name)
2090 {
2091  // FIXME: Finalize what we want to store in octave_builtin, then add functions
2092  // to access these values in octave_value
2093  octave_value ov_builtin = symbol_table::find (name);
2094  return dynamic_cast<octave_builtin *> (ov_builtin.internal_rep ());
2095 }
2096 
2097 void
2098 jit_typeinfo::register_generic (const std::string& name, jit_type *result,
2099  const std::vector<jit_type *>& args)
2100 {
2101  octave_builtin *builtin = find_builtin (name);
2102  if (! builtin)
2103  return;
2104 
2105  std::vector<jit_type *> fn_args (args.size () + 1);
2106  fn_args[0] = builtins[name];
2107  std::copy (args.begin (), args.end (), fn_args.begin () + 1);
2108  jit_function fn = create_internal (name, result, fn_args);
2109  fn.mark_can_error ();
2110  llvm::BasicBlock *block = fn.new_block ();
2111  builder.SetInsertPoint (block);
2112  llvm::Type *any_t = any->to_llvm ();
2113  llvm::ArrayType *array_t = llvm::ArrayType::get (any_t, args.size ());
2114  llvm::Value *array = llvm::UndefValue::get (array_t);
2115  for (size_t i = 0; i < args.size (); ++i)
2116  {
2117  llvm::Value *arg = fn.argument (builder, i + 1);
2118  jit_function agrab = get_grab (args[i]);
2119  if (agrab.valid ())
2120  arg = agrab.call (builder, arg);
2121  jit_function acast = cast (any, args[i]);
2122  array = builder.CreateInsertValue (array, acast.call (builder, arg), i);
2123  }
2124 
2125  llvm::Value *array_mem = builder.CreateAlloca (array_t);
2126  builder.CreateStore (array, array_mem);
2127  array = builder.CreateBitCast (array_mem, any_t->getPointerTo ());
2128 
2129  jit_type *jintTy = intN (sizeof (octave_builtin::fcn) * 8);
2130  llvm::Type *intTy = jintTy->to_llvm ();
2131  size_t fcn_int = reinterpret_cast<size_t> (builtin->function ());
2132  llvm::Value *fcn = llvm::ConstantInt::get (intTy, fcn_int);
2133  llvm::Value *nargin = llvm::ConstantInt::get (intTy, args.size ());
2134  size_t result_int = reinterpret_cast<size_t> (result);
2135  llvm::Value *res_llvm = llvm::ConstantInt::get (intTy, result_int);
2136  llvm::Value *ret = any_call.call (builder, fcn, nargin, array, res_llvm);
2137 
2138  jit_function cast_result = cast (result, any);
2139  fn.do_return (builder, cast_result.call (builder, ret));
2141 }
2142 
2145 {
2146  jit_function ret = create_internal (fn.name () + "_reverse",
2147  fn.result (), fn.argument_type (1),
2148  fn.argument_type (0));
2149  if (fn.can_error ())
2150  ret.mark_can_error ();
2151 
2152  llvm::BasicBlock *body = ret.new_block ();
2153  builder.SetInsertPoint (body);
2154  llvm::Value *result = fn.call (builder, ret.argument (builder, 1),
2155  ret.argument (builder, 0));
2156  if (ret.result ())
2157  ret.do_return (builder, result);
2158  else
2159  ret.do_return (builder);
2160 
2161  return ret;
2162 }
2163 
2164 llvm::Value *
2166 {
2167  llvm::Type *complex_ret = instance->complex_ret;
2168  llvm::Value *real = bld.CreateExtractValue (cplx, 0);
2169  llvm::Value *imag = bld.CreateExtractValue (cplx, 1);
2170  llvm::Value *ret = llvm::UndefValue::get (complex_ret);
2171 
2172  unsigned int re_idx[] = {0, 0};
2173  unsigned int im_idx[] = {0, 1};
2174  ret = bld.CreateInsertValue (ret, real, re_idx);
2175  return bld.CreateInsertValue (ret, imag, im_idx);
2176 }
2177 
2178 llvm::Value *
2180 {
2181  unsigned int re_idx[] = {0, 0};
2182  unsigned int im_idx[] = {0, 1};
2183 
2184  llvm::Type *complex_t = get_complex ()->to_llvm ();
2185  llvm::Value *real = bld.CreateExtractValue (result, re_idx);
2186  llvm::Value *imag = bld.CreateExtractValue (result, im_idx);
2187  llvm::Value *ret = llvm::UndefValue::get (complex_t);
2188 
2189  ret = bld.CreateInsertValue (ret, real, 0);
2190  return bld.CreateInsertValue (ret, imag, 1);
2191 }
2192 
2193 llvm::Value *
2195 {
2196  return builder.CreateExtractValue (cx, 0);
2197 }
2198 
2199 llvm::Value *
2200 jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real)
2201 {
2202  return builder.CreateInsertValue (cx, real, 0);
2203 }
2204 
2205 llvm::Value *
2207 {
2208  return builder.CreateExtractValue (cx, 1);
2209 }
2210 
2211 llvm::Value *
2212 jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag)
2213 {
2214  return builder.CreateInsertValue (cx, imag, 1);
2215 }
2216 
2217 llvm::Value *
2218 jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag)
2219 {
2220  llvm::Value *ret = llvm::UndefValue::get (complex->to_llvm ());
2221  ret = complex_real (ret, real);
2222  return complex_imag (ret, imag);
2223 }
2224 
2225 void
2227 {
2228  std::stringstream tname;
2229  tname << "int" << nbits;
2230  ints[nbits] = new_type (tname.str (), any, llvm::Type::getIntNTy (context,
2231  nbits));
2232 }
2233 
2234 jit_type *
2235 jit_typeinfo::intN (size_t nbits) const
2236 {
2237  std::map<size_t, jit_type *>::const_iterator iter = ints.find (nbits);
2238  if (iter != ints.end ())
2239  return iter->second;
2240 
2241  throw jit_fail_exception ("No such integer type");
2242 }
2243 
2244 jit_type *
2246 {
2247  if (ov.is_function ())
2248  {
2249  // FIXME: This is ugly, we need to finalize how we want to to this, then
2250  // have octave_value fully support the needed functionality
2251  octave_builtin *builtin
2252  = dynamic_cast<octave_builtin *> (ov.internal_rep ());
2253  return builtin && builtin->to_jit () ? builtin->to_jit ()
2254  : unknown_function;
2255  }
2256 
2257  if (ov.is_range ())
2258  return get_range ();
2259 
2260  if (ov.is_double_type () && ! ov.is_complex_type ())
2261  {
2262  if (ov.is_real_scalar ())
2263  return get_scalar ();
2264 
2265  if (ov.is_matrix_type ())
2266  return get_matrix ();
2267  }
2268 
2269  if (ov.is_complex_scalar ())
2270  {
2271  Complex cv = ov.complex_value ();
2272 
2273  // We don't really represent complex values, instead we represent
2274  // complex_or_scalar. If the imag value is zero, we assume a scalar.
2275  if (cv.imag () != 0)
2276  return get_complex ();
2277  }
2278 
2279  return get_any ();
2280 }
2281 
2282 #endif
jit_type * result(void) const
Definition: jit-typeinfo.h:294
void do_return(llvm::IRBuilderD &builder, llvm::Value *rval=0, bool verify=true)
octave_idx_type slice_len
Definition: jit-typeinfo.h:100
Array< octave_idx_type > to_idx(const signature_vec &types) const
void stash_jit(jit_type &type)
Definition: ov-builtin.cc:162
llvm::Module * module
Definition: jit-typeinfo.h:791
static llvm::Value * unpack_complex(llvm::IRBuilderD &bld, llvm::Value *result)
void add_binary_fcmp(jit_type *ty, int op, int llvm_op)
bool is_range(void) const
Definition: ov.h:571
jit_type * unknown_function
Definition: jit-typeinfo.h:811
jit_type * complex
Definition: jit-typeinfo.h:810
jit_function * generate_matrix(const signature_vec &types) const
static int xisint(double x)
Complex octave_jit_pow_scalar_scalar(double lhs, double rhs)
Definition: jit-util.h:41
virtual void do_initialize(void)
static jit_type * get_matrix(void)
Definition: jit-typeinfo.h:448
octave_base_value * octave_jit_grab_any(octave_base_value *obv)
octave_base_value * octave_jit_cast_any_complex(Complex c)
bool valid(void) const
Definition: jit-typeinfo.h:250
const std::string & name(void) const
Definition: jit-typeinfo.h:142
llvm::Value * complex_imag(llvm::Value *cx)
llvm::Type * sig_atomic_type
Definition: jit-typeinfo.h:798
double octave_jit_cast_scalar_any(octave_base_value *obv)
void octave_jit_gripe_nan_to_logical_conversion(void)
octave_value_list(* fcn)(const octave_value_list &, int)
Definition: ov-builtin.h:45
jit_operation for_check_fn
Definition: jit-typeinfo.h:824
octave_base_value * octave_jit_call(octave_builtin::fcn fn, size_t nargin, octave_base_value **argin, jit_type *result_type)
void add_binary_icmp(jit_type *ty, int op, int llvm_op)
jit_type * index
Definition: jit-typeinfo.h:809
octave_base_value * octave_jit_binary_any_any(octave_value::binary_op op, octave_base_value *lhs, octave_base_value *rhs)
llvm::Type * to_llvm(void) const
Definition: jit-typeinfo.h:151
jit_paren_subsref paren_subsref_fn
Definition: jit-typeinfo.h:828
static std::string binary_op_as_string(binary_op)
Definition: ov.cc:190
bool is_function(void) const
Definition: ov.h:695
static void initialize(llvm::Module *m, llvm::ExecutionEngine *e)
virtual jit_function * generate(const signature_vec &types) const
jit_type * to_jit(void) const
Definition: ov-builtin.cc:156
octave_idx_type length(void) const
Definition: oct-obj.h:89
jit_block * parent(void) const
Definition: jit-ir.h:438
octave_idx_type nelem(void) const
Definition: Range.h:64
jit_block * mparent
Definition: jit-ir.h:474
bool mpointer_arg[jit_convention::length]
Definition: jit-typeinfo.h:207
virtual Range range_value(void) const
Definition: ov-base.cc:926
octave_base_value * octave_jit_create_undef(void)
void register_generic(const std::string &name, jit_type *result, jit_type *arg0)
Definition: jit-typeinfo.h:753
jit_matrix octave_jit_paren_subsasgn_matrix_range(jit_matrix *mat, jit_range *index, double value)
jit_type * scalar_ptr
Definition: jit-typeinfo.h:804
std::ostream & operator<<(std::ostream &os, const jit_range &rng)
llvm::Type * llvm_type
Definition: jit-typeinfo.h:201
bool is_complex_scalar(void) const
Definition: ov.h:541
Definition: Range.h:31
bool sret(void) const
Definition: jit-typeinfo.h:288
jit_type * new_type(const std::string &name, jit_type *parent, llvm::Type *llvm_type, bool skip_paren=false)
binary_op
Definition: ov.h:87
FloatComplex(* fptr)(const FloatComplex &, float, int, octave_idx_type &)
Definition: lo-specfun.cc:1732
Complex octave_jit_complex_div(Complex lhs, Complex rhs)
bool msret[jit_convention::length]
Definition: jit-typeinfo.h:206
static llvm::Value * pack_complex(llvm::IRBuilderD &bld, llvm::Value *cplx)
void error(const char *fmt,...)
Definition: error.cc:476
void set_packed_type(jit_convention::type cc, llvm::Type *ty)
Definition: jit-typeinfo.h:196
jit_type * type(void) const
Definition: jit-ir.h:208
void add_builtin(const std::string &name)
jit_type * intN(size_t nbits) const
void mark_sret(jit_convention::type cc)
Definition: jit-typeinfo.h:168
llvm::Type * mpacked_type[jit_convention::length]
Definition: jit-typeinfo.h:212
T * jit_slice_data(void) const
Definition: Array.h:745
jit_operation destroy_fn
Definition: jit-typeinfo.h:821
llvm::Module * module
Definition: jit-typeinfo.h:407
llvm::Value * complex_new(llvm::Value *real, llvm::Value *imag)
jit_type * mresult
Definition: jit-typeinfo.h:308
void add_overload(const jit_function &func)
Definition: jit-typeinfo.h:328
void gripe_library_execution_error(void)
Definition: gripes.cc:208
std::vector< jit_type * > signature_vec
Definition: jit-typeinfo.h:324
jit_function mirror_binary(const jit_function &fn)
std::vector< jit_type * > id_to_type
Definition: jit-typeinfo.h:800
octave_idx_type nelem
Definition: jit-typeinfo.h:61
convert_fn pack(jit_convention::type cc)
Definition: jit-typeinfo.h:182
std::map< size_t, jit_type * > ints
Definition: jit-typeinfo.h:812
void erase(void)
jit_operation release_fn
Definition: jit-typeinfo.h:820
static llvm::IRBuilder builder(llvm::getGlobalContext())
static llvm::Type * get_scalar_llvm(void)
Definition: jit-typeinfo.h:452
void gripe_invalid_index(void)
jit_type * range
Definition: jit-typeinfo.h:806
jit_type * boolean
Definition: jit-typeinfo.h:808
llvm::TerminatorInst * to_llvm(void) const
Definition: jit-ir.cc:701
double base
Definition: jit-typeinfo.h:58
void mark_pointer_arg(jit_convention::type cc)
Definition: jit-typeinfo.h:176
jit_range octave_jit_cast_range_any(octave_base_value *obv)
llvm::ExecutionEngine * engine
Definition: jit-typeinfo.h:408
static jit_type * get_range(void)
Definition: jit-typeinfo.h:459
Complex octave_jit_cast_complex_any(octave_base_value *obv)
llvm::Function * llvm_function
Definition: jit-typeinfo.h:307
llvm::GlobalVariable * lerror_state
Definition: jit-typeinfo.h:795
llvm::Value * call(llvm::IRBuilderD &builder, const std::vector< jit_value * > &in_args) const
std::map< std::string, jit_type * > builtins
Definition: jit-typeinfo.h:813
octave_idx_type nelem(void) const
Number of elements in the array.
Definition: Array.h:271
jit_matrix octave_jit_grab_matrix(jit_matrix *m)
#define JIT_FN(fn)
jit_function create_external(llvm::ExecutionEngine *ee, T fn, const llvm::Twine &name, jit_type *ret, const std::vector< jit_type * > &args=std::vector< jit_type * >())
Definition: jit-typeinfo.h:680
jit_function paren_scalar
Definition: jit-typeinfo.h:430
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:337
std::ostream & jit_print(std::ostream &os, jit_type *atype)
Definition: jit-typeinfo.cc:80
static const jit_operation & cast(jit_type *result)
Definition: jit-typeinfo.h:550
virtual Complex complex_value(bool=false) const
Definition: ov-base.cc:574
static jit_type * get_complex(void)
Definition: jit-typeinfo.h:470
void octave_jit_gindex_range(int nd, int dim, octave_idx_type iext, octave_idx_type ext)
void add_mapping(llvm::ExecutionEngine *engine, T fn)
Definition: jit-typeinfo.h:245
const jit_function & do_generate(const signature_vec &types) const
const jit_function & overload(const signature_vec &types) const
jit_operation print_fn
Definition: jit-typeinfo.h:822
bool pointer_arg(jit_convention::type cc) const
Definition: jit-typeinfo.h:174
int * jit_ref_count(void)
WARNING: Only call these functions from jit.
Definition: Array.h:743
jit_matrix octave_jit_paren_scalar_subsasgn(jit_matrix *mat, double *indices, octave_idx_type idx_count, double value)
llvm::IRBuilderD & builder
Definition: jit-typeinfo.h:842
void octave_jit_release_any(octave_base_value *obv)
size_t mid
Definition: jit-ir.h:473
virtual double double_value(bool=false) const
Definition: ov-base.cc:517
fcn function(void) const
Definition: ov-builtin.cc:168
U * slice_data
Definition: jit-typeinfo.h:99
bool is_real_scalar(void) const
Definition: ov.h:535
jit_type * matrix
Definition: jit-typeinfo.h:802
std::vector< jit_operation > binary_ops
Definition: jit-typeinfo.h:817
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:76
static void gripe_index_out_of_range(void)
Definition: idx-vector.cc:51
void octave_jit_print_matrix(jit_matrix *m)
static void gripe_bad_result(void)
bool is_matrix_type(void) const
Definition: ov.h:660
void gripe_nan_to_logical_conversion(void)
void resize1(octave_idx_type n, const T &rfv)
Definition: Array.cc:913
jit_convention::type call_conv
Definition: jit-typeinfo.h:310
llvm::StructType * complex_ret
Definition: jit-typeinfo.h:815
bool is_double_type(void) const
Definition: ov.h:608
jit_operation for_init_fn
Definition: jit-typeinfo.h:823
std::vector< jit_operation > unary_ops
Definition: jit-typeinfo.h:818
virtual jit_function * generate_matrix(const signature_vec &types) const
int error_state
Definition: error.cc:101
jit_type * do_type_of(const octave_value &ov) const
bool is_complex_type(void) const
Definition: ov.h:654
const jit_function & do_end(jit_value *value, jit_value *index, jit_value *count)
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1033
octave_int< T > pow(const octave_int< T > &a, const octave_int< T > &b)
jit_type * any_ptr
Definition: jit-typeinfo.h:805
jit_operation grab_fn
Definition: jit-typeinfo.h:819
bool can_error(void) const
Definition: jit-typeinfo.h:290
void create_int(size_t nbits)
llvm::Value * do_insert_error_check(llvm::IRBuilderD &bld)
jit_type * argument_type(size_t idx) const
Definition: jit-typeinfo.h:296
static jit_type * get_scalar(void)
Definition: jit-typeinfo.h:450
octave_builtin * find_builtin(const std::string &name)
sig_atomic_t octave_interrupt_state
Definition: cquit.c:80
void stash_name(const std::string &aname)
Definition: jit-typeinfo.h:359
Complex octave_jit_pow_complex_scalar(Complex lhs, double rhs)
llvm::Value * complex_real(llvm::Value *cx)
octave_base_value * octave_jit_cast_any_matrix(jit_matrix *m)
llvm::Module * module
Definition: jit-typeinfo.h:306
Definition: dMatrix.h:35
OCTAVE_API double D_NINT(double x)
Definition: lo-mappers.h:240
octave_idx_type * dimensions
Definition: jit-typeinfo.h:101
bool operator()(const signature_vec *lhs, const signature_vec *rhs) const
jit_operation logically_true_fn
Definition: jit-typeinfo.h:826
void add_binary_op(jit_type *ty, int op, int llvm_op)
jit_function create_identity(jit_type *type)
Complex octave_jit_pow_scalar_complex(double lhs, Complex rhs)
double arg(double x)
Definition: lo-mappers.h:37
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:111
T & xelem(octave_idx_type n)
Definition: Array.h:353
void update(void)
Definition: jit-typeinfo.h:78
jit_matrix octave_jit_paren_subsasgn_impl(jit_matrix *mat, octave_idx_type index, double value)
virtual ~jit_operation(void)
void grab(void)
Definition: ov-base.h:775
virtual jit_function * generate_matrix(const signature_vec &types) const =0
convert_fn unpack(jit_convention::type cc)
Definition: jit-typeinfo.h:187
Handles the reference counting for all the derived classes.
Definition: Array.h:45
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:233
void octave_jit_print_scalar(const char *name, double value)
Definition: jit-typeinfo.cc:95
static const jit_function & get_release(jit_type *type)
Definition: jit-typeinfo.h:500
int * ref_count
Definition: jit-typeinfo.h:97
double octave_jit_end_matrix(jit_matrix *mat, octave_idx_type idx, octave_idx_type count)
jit_operation make_range_fn
Definition: jit-typeinfo.h:827
jit_function create_internal(const llvm::Twine &name, jit_type *ret, const std::vector< jit_type * > &args=std::vector< jit_type * >())
Definition: jit-typeinfo.h:714
#define octave_stdout
Definition: pager.h:144
jit_paren_subsasgn paren_subsasgn_fn
Definition: jit-typeinfo.h:829
octave_value_list ovl(const octave_value &a0)
Definition: oct-obj.h:178
jit_type * ty
Definition: jit-ir.h:271
static void make_indices(double *indices, octave_idx_type idx_count, Array< idx_vector > &result)
static jit_type * get_scalar_ptr(void)
Definition: jit-typeinfo.h:455
jit_type(const std::string &aname, jit_type *aparent, llvm::Type *allvm_type, bool askip_paren, int aid)
octave_base_value * octave_jit_cast_any_scalar(double value)
octave_base_value * octave_jit_cast_any_range(jit_range *rng)
jit_function create_function(jit_convention::type cc, const llvm::Twine &name, jit_type *ret, const std::vector< jit_type * > &args=std::vector< jit_type * >())
void initialize(llvm::Module *amodule, llvm::ExecutionEngine *aengine)
Definition: jit-typeinfo.h:388
double inc
Definition: jit-typeinfo.h:60
void register_intrinsic(const std::string &name, size_t id, jit_type *result, jit_type *arg0)
Definition: jit-typeinfo.h:743
Complex complex_value(bool frc_str_conv=false) const
Definition: ov.h:785
octave_idx_type octave_jit_compute_nelem(double base, double limit, double inc)
static size_t next_id(bool reset=false)
Definition: jit-ir.h:462
convert_fn munpack[jit_convention::length]
Definition: jit-typeinfo.h:210
llvm::Value *(* convert_fn)(llvm::IRBuilderD &, llvm::Value *)
Definition: jit-typeinfo.h:136
convert_fn mpack[jit_convention::length]
Definition: jit-typeinfo.h:209
bool all_elements_are_ints(void) const
Definition: Range.cc:40
void print_with_name(std::ostream &os, const std::string &name) const
Definition: ov.h:1040
PASS_T value(void) const
Definition: jit-ir.h:514
static int convert(int x, int ibase, int obase)
Definition: file-io.cc:2208
void add_print(jit_type *ty, void *fptr)
Complex octave_jit_pow_complex_complex(Complex lhs, Complex rhs)
void octave_jit_ginvalid_index(void)
jit_operation for_index_fn
Definition: jit-typeinfo.h:825
jit_function any_call
Definition: jit-typeinfo.h:834
generated_map generated
Definition: jit-typeinfo.h:375
jit_operation end_fn
Definition: jit-typeinfo.h:831
bool is_undefined(void) const
Definition: ov.h:523
llvm::BasicBlock * new_block(const std::string &aname="body", llvm::BasicBlock *insert_before=0)
static const jit_function & get_grab(jit_type *type)
Definition: jit-typeinfo.h:490
void assign(const idx_vector &i, const Array< T > &rhs, const T &rfv)
Indexed assignment (always with resize & fill).
Definition: Array.cc:1140
void set_pack(jit_convention::type cc, convert_fn fn)
Definition: jit-typeinfo.h:184
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:162
int type_id(void) const
Definition: jit-typeinfo.h:145
virtual void do_initialize(void)
double limit
Definition: jit-typeinfo.h:59
static jit_typeinfo * instance
Definition: jit-typeinfo.h:789
virtual jit_function * generate(const signature_vec &types) const
static jit_type * get_any(void)
Definition: jit-typeinfo.h:446
llvm::Value * argument(llvm::IRBuilderD &builder, size_t idx) const
Complex octave_jit_complex_mul(Complex lhs, Complex rhs)
jit_type * any
Definition: jit-typeinfo.h:801
void do_add_mapping(llvm::ExecutionEngine *engine, void *fn)
std::complex< double > Complex
Definition: oct-cmplx.h:29
const T * fortran_vec(void) const
Definition: Array.h:481
void octave_jit_print_any(const char *name, octave_base_value *obv)
Definition: jit-typeinfo.cc:89
static std::string unary_op_as_string(unary_op)
Definition: ov.cc:114
llvm::ExecutionEngine * engine
Definition: jit-typeinfo.h:792
octave_base_value * internal_rep(void) const
Definition: ov.h:1114
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:156
llvm::Type * to_llvm_arg(void) const
void release(void)
Definition: ov-base.h:782
virtual NDArray array_value(bool=false) const
Definition: ov-base.cc:558
llvm::Function * to_llvm(void) const
Definition: jit-typeinfo.h:285
jit_operation end1_fn
Definition: jit-typeinfo.h:830
double octave_jit_paren_scalar(jit_matrix *mat, double *indicies, octave_idx_type idx_count)
jit_type * scalar
Definition: jit-typeinfo.h:803
void mark_can_error(void)
Definition: jit-typeinfo.h:292
std::vector< jit_operation > casts
Definition: jit-typeinfo.h:837
jit_matrix octave_jit_cast_matrix_any(octave_base_value *obv)
octave_value & xelem(octave_idx_type i)
Definition: oct-obj.h:143
llvm::Type * packed_type(jit_convention::type cc)
Definition: jit-typeinfo.h:193
unary_op
Definition: ov.h:74
void set_unpack(jit_convention::type cc, convert_fn fn)
Definition: jit-typeinfo.h:189
std::vector< jit_function > identities
Definition: jit-typeinfo.h:840
llvm::Value * create_arg_array(llvm::IRBuilderD &builder, const jit_function &fn, size_t start_idx, size_t end_idx) const
virtual void print_with_name(std::ostream &output_buf, const std::string &name, bool print_padding=true)
Definition: ov-base.cc:436
jit_function paren_scalar
Definition: jit-typeinfo.h:419
jit_typeinfo(llvm::Module *m, llvm::ExecutionEngine *e)
IRBuilder< true, ConstantFolder, IRBuilderDefaultInserter< true > > IRBuilderD
Definition: jit-util.h:71
void gripe_divide_by_zero(void)
Definition: gripes.cc:195
std::string name(void) const
void octave_jit_release_matrix(jit_matrix *m)
jit_operation create_undef_fn
Definition: jit-typeinfo.h:832
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
F77_RET_T const double * x
llvm::GlobalVariable * loctave_interrupt_state
Definition: jit-typeinfo.h:796
static bool scalar(const dim_vector &dims)
Definition: ov-struct.cc:736
static jit_type * get_index(void)
Definition: jit-typeinfo.h:465
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:210
octave_value do_binary_op(octave_value::binary_op op, const octave_value &v1, const octave_value &v2)
Definition: ov.cc:1978
std::vector< Array< jit_function > > overloads
Definition: jit-typeinfo.h:377
std::vector< jit_type * > args
Definition: jit-typeinfo.h:309
llvm::Value * do_insert_interrupt_check(llvm::IRBuilderD &bld)
static octave_value find(const std::string &name, const octave_value_list &args=octave_value_list(), bool skip_variables=false, bool local_funcs=true)
Definition: symtab.cc:1250
bool all_elements_are_ints() const
size_t id(void) const
Definition: jit-ir.h:454