GNU Octave  4.2.1
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-2017 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 #if defined (HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
32 
33 #if defined (HAVE_LLVM)
34 
35 #include "jit-typeinfo.h"
36 
37 #if defined (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 #if defined (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 #if defined (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
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.numel ();
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 {
219 }
220 
221 extern "C" void
223 {
224  // FIXME: 0-argument form of octave::err_invalid_index removed in cset dd6345fd8a97
225  // Report -1 as the bad index for all occurrences.
226  octave::err_invalid_index (static_cast<octave_idx_type> (-1));
227 }
228 
229 extern "C" void
231  octave_idx_type ext)
232 {
233  octave::err_index_out_of_range (nd, dim, iext, ext);
234 }
235 
236 extern "C" jit_matrix
238  double value)
239 {
240  NDArray *array = mat->array;
241  if (array->numel () < index)
242  array->resize1 (index);
243 
244  double *data = array->fortran_vec ();
245  data[index - 1] = value;
246 
247  mat->update ();
248  return *mat;
249 }
250 
251 static void
252 make_indices (double *indices, octave_idx_type idx_count,
254 {
255  result.resize (dim_vector (1, idx_count));
256  for (octave_idx_type i = 0; i < idx_count; ++i)
257  result(i) = idx_vector (indices[i]);
258 }
259 
260 extern "C" double
261 octave_jit_paren_scalar (jit_matrix *mat, double *indicies,
262  octave_idx_type idx_count)
263 {
264  // FIXME: Replace this with a more optimal version
265  Array<idx_vector> idx;
266  make_indices (indicies, idx_count, idx);
267 
268  Array<double> ret = mat->array->index (idx);
269 
270  return ret.xelem (0);
271 }
272 
273 extern "C" jit_matrix
275  octave_idx_type idx_count, double value)
276 {
277  // FIXME: Replace this with a more optimal version
278  jit_matrix ret;
279 
280  Array<idx_vector> idx;
281  make_indices (indices, idx_count, idx);
282 
283  Matrix temp (1, 1);
284  temp.xelem(0) = value;
285  mat->array->assign (idx, temp);
286  ret.update (mat->array);
287 
288  return ret;
289 }
290 
291 extern "C" jit_matrix
293  double value)
294 {
295  NDArray *array = mat->array;
296  bool done = false;
297 
298  // optimize for the simple case (no resizing and no errors)
299  if (*array->jit_ref_count () == 1
300  && index->all_elements_are_ints ())
301  {
302  // this code is similar to idx_vector::fill, but we avoid allocating an
303  // idx_vector and its associated rep
304  octave_idx_type start = static_cast<octave_idx_type> (index->base) - 1;
305  octave_idx_type step = static_cast<octave_idx_type> (index->inc);
306  octave_idx_type nelem = index->nelem;
307  octave_idx_type final = start + nelem * step;
308  if (step < 0)
309  {
310  step = -step;
311  std::swap (final, start);
312  }
313 
314  if (start >= 0 && final < mat->slice_len)
315  {
316  done = true;
317 
318  double *data = array->jit_slice_data ();
319  if (step == 1)
320  std::fill (data + start, data + start + nelem, value);
321  else
322  {
323  for (octave_idx_type i = start; i < final; i += step)
324  data[i] = value;
325  }
326  }
327  }
328 
329  if (! done)
330  {
331  idx_vector idx (*index);
332  NDArray avalue (dim_vector (1, 1));
333  avalue.xelem (0) = value;
334  array->assign (idx, avalue);
335  }
336 
337  jit_matrix ret;
338  ret.update (array);
339  return ret;
340 }
341 
342 extern "C" double
344  octave_idx_type count)
345 {
346  octave_idx_type ndim = mat->dimensions[-1];
347  if (ndim == count)
348  return mat->dimensions[idx];
349  else if (ndim > count)
350  {
351  if (idx == count - 1)
352  {
353  double ret = mat->dimensions[idx];
354  for (octave_idx_type i = idx + 1; i < ndim; ++i)
355  ret *= mat->dimensions[idx];
356  return ret;
357  }
358 
359  return mat->dimensions[idx];
360  }
361  else // ndim < count
362  return idx < ndim ? mat->dimensions[idx] : 1;
363 }
364 
365 extern "C" octave_base_value *
367 {
368  octave_value undef;
369  octave_base_value *ret = undef.internal_rep ();
370  ret->grab ();
371 
372  return ret;
373 }
374 
375 extern "C" Complex
377 {
378  if (lhs.imag () == 0 && rhs.imag() == 0)
379  return Complex (lhs.real () * rhs.real (), 0);
380 
381  return lhs * rhs;
382 }
383 
384 extern "C" Complex
386 {
387  // see src/OPERATORS/op-cs-cs.cc
388  if (rhs == 0.0)
390 
391  return lhs / rhs;
392 }
393 
394 // FIXME: CP form src/xpow.cc
395 static inline int
396 xisint (double x)
397 {
398  return (octave::math::x_nint (x) == x
399  && ((x >= 0 && x < std::numeric_limits<int>::max ())
400  || (x <= 0 && x > std::numeric_limits<int>::min ())));
401 }
402 
403 extern "C" Complex
404 octave_jit_pow_scalar_scalar (double lhs, double rhs)
405 {
406  // FIXME: almost CP from src/xpow.cc
407  if (lhs < 0.0 && ! xisint (rhs))
408  return std::pow (Complex (lhs), rhs);
409  return std::pow (lhs, rhs);
410 }
411 
412 extern "C" Complex
414 {
415  if (lhs.imag () == 0 && rhs.imag () == 0)
416  return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ());
417  return std::pow (lhs, rhs);
418 }
419 
420 extern "C" Complex
422 {
423  if (lhs.imag () == 0)
424  return octave_jit_pow_scalar_scalar (lhs.real (), rhs);
425  return std::pow (lhs, rhs);
426 }
427 
428 extern "C" Complex
430 {
431  if (rhs.imag () == 0)
432  return octave_jit_pow_scalar_scalar (lhs, rhs.real ());
433  return std::pow (lhs, rhs);
434 }
435 
436 extern "C" void
438 {
439  std::cout << *m << std::endl;
440 }
441 
442 OCTAVE_NORETURN static
443 void
445 {
446  error ("incorrect type information given to the JIT compiler");
447 }
448 
449 // FIXME: Add support for multiple outputs
450 extern "C" octave_base_value *
452  octave_base_value **argin, jit_type *result_type)
453 {
454  octave_value_list ovl (nargin);
455  for (size_t i = 0; i < nargin; ++i)
456  ovl.xelem (i) = octave_value (argin[i]);
457 
458  ovl = fn (ovl, 1);
459 
460  // FIXME: Check result_type somehow
461  if (result_type)
462  {
463  if (ovl.length () < 1)
464  err_bad_result ();
465 
466  octave_value result = ovl.xelem(0);
467  octave_base_value *ret = result.internal_rep ();
468  ret->grab ();
469  return ret;
470  }
471 
472  if (! (ovl.empty ()
473  || (ovl.length () == 1 && ovl.xelem (0).is_undefined ())))
474  err_bad_result ();
475 
476  return 0;
477 }
478 
479 // -------------------- jit_range --------------------
480 bool
482 {
483  Range r (*this);
484  return r.all_elements_are_ints ();
485 }
486 
487 std::ostream&
488 operator<< (std::ostream& os, const jit_range& rng)
489 {
490  return os << "Range[" << rng.base << ", " << rng.limit << ", " << rng.inc
491  << ", " << rng.nelem << "]";
492 }
493 
494 // -------------------- jit_matrix --------------------
495 
496 std::ostream&
497 operator<< (std::ostream& os, const jit_matrix& mat)
498 {
499  return os << "Matrix[" << mat.ref_count << ", " << mat.slice_data << ", "
500  << mat.slice_len << ", " << mat.dimensions << ", "
501  << mat.array << "]";
502 }
503 
504 // -------------------- jit_type --------------------
505 jit_type::jit_type (const std::string& aname, jit_type *aparent,
506  llvm::Type *allvm_type, bool askip_paren, int aid) :
507  mname (aname), mparent (aparent), llvm_type (allvm_type), mid (aid),
508  mdepth (aparent ? aparent->mdepth + 1 : 0), mskip_paren (askip_paren)
509 {
510  std::memset (msret, 0, sizeof (msret));
511  std::memset (mpointer_arg, 0, sizeof (mpointer_arg));
512  std::memset (mpack, 0, sizeof (mpack));
513  std::memset (munpack, 0, sizeof (munpack));
514 
515  for (size_t i = 0; i < jit_convention::length; ++i)
517 }
518 
519 llvm::Type *
521 {
522  return llvm_type ? llvm_type->getPointerTo () : 0;
523 }
524 
525 // -------------------- jit_function --------------------
526 jit_function::jit_function () : module (0), llvm_function (0), mresult (0),
527  call_conv (jit_convention::length),
528  mcan_error (false)
529 { }
530 
531 jit_function::jit_function (llvm::Module *amodule,
532  jit_convention::type acall_conv,
533  const llvm::Twine& aname, jit_type *aresult,
534  const std::vector<jit_type *>& aargs)
535  : module (amodule), mresult (aresult), args (aargs), call_conv (acall_conv),
536  mcan_error (false)
537 {
538  llvm::SmallVector<llvm::Type *, 15> llvm_args;
539 
540  llvm::Type *rtype = llvm::Type::getVoidTy (context);
541  if (mresult)
542  {
543  rtype = mresult->packed_type (call_conv);
544  if (sret ())
545  {
546  llvm_args.push_back (rtype->getPointerTo ());
547  rtype = llvm::Type::getVoidTy (context);
548  }
549  }
550 
551  for (std::vector<jit_type *>::const_iterator iter = args.begin ();
552  iter != args.end (); ++iter)
553  {
554  jit_type *ty = *iter;
555  assert (ty);
556  llvm::Type *argty = ty->packed_type (call_conv);
557  if (ty->pointer_arg (call_conv))
558  argty = argty->getPointerTo ();
559 
560  llvm_args.push_back (argty);
561  }
562 
563  // we mark all functinos as external linkage because this prevents llvm
564  // from getting rid of always inline functions
565  llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false);
566  llvm_function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage,
567  aname, module);
568 
569  if (sret ())
570  {
571 #if defined (FUNCTION_ADDATTRIBUTE_ARG_IS_ATTRIBUTES)
572  llvm::AttrBuilder attr_builder;
573  attr_builder.addAttribute (llvm::Attributes::StructRet);
574  llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
575  llvm_function->addAttribute (1, attrs);
576 #else
577  llvm_function->addAttribute (1, llvm::Attribute::StructRet);
578 #endif
579  }
580 
582 #if defined (FUNCTION_ADDFNATTR_ARG_IS_ATTRIBUTES)
583  llvm_function->addFnAttr (llvm::Attributes::AlwaysInline);
584 #else
585  llvm_function->addFnAttr (llvm::Attribute::AlwaysInline);
586 #endif
587 }
588 
590  const std::vector<jit_type *>& aargs)
591  : module (fn.module), llvm_function (fn.llvm_function), mresult (aresult),
592  args (aargs), call_conv (fn.call_conv), mcan_error (fn.mcan_error)
593 { }
594 
596  : module (fn.module), llvm_function (fn.llvm_function), mresult (fn.mresult),
597  args (fn.args), call_conv (fn.call_conv), mcan_error (fn.mcan_error)
598 { }
599 
600 void
602 {
603  if (! llvm_function)
604  return;
605 
606  llvm_function->eraseFromParent ();
607  llvm_function = 0;
608 }
609 
611 jit_function::name (void) const
612 {
613  return llvm_function->getName ();
614 }
615 
616 llvm::BasicBlock *
618  llvm::BasicBlock *insert_before)
619 {
620  return llvm::BasicBlock::Create (context, aname, llvm_function,
621  insert_before);
622 }
623 
624 llvm::Value *
626  const std::vector<jit_value *>& in_args) const
627 {
628  if (! valid ())
629  throw jit_fail_exception ("Call not implemented");
630 
631  assert (in_args.size () == args.size ());
632  std::vector<llvm::Value *> llvm_args (args.size ());
633  for (size_t i = 0; i < in_args.size (); ++i)
634  llvm_args[i] = in_args[i]->to_llvm ();
635 
636  return call (builder, llvm_args);
637 }
638 
639 llvm::Value *
641  const std::vector<llvm::Value *>& in_args) const
642 {
643  if (! valid ())
644  throw jit_fail_exception ("Call not implemented");
645 
646  assert (in_args.size () == args.size ());
647  llvm::SmallVector<llvm::Value *, 10> llvm_args;
648  llvm_args.reserve (in_args.size () + sret ());
649 
650  llvm::BasicBlock *insert_block = builder.GetInsertBlock ();
651  llvm::Function *parent = insert_block->getParent ();
652  assert (parent);
653 
654  // we insert allocas inside the prelude block to prevent stack overflows
655  llvm::BasicBlock& prelude = parent->getEntryBlock ();
656  llvm::IRBuilder<> pre_builder (&prelude, prelude.begin ());
657 
658  llvm::AllocaInst *sret_mem = 0;
659  if (sret ())
660  {
661  sret_mem = pre_builder.CreateAlloca (mresult->packed_type (call_conv));
662  llvm_args.push_back (sret_mem);
663  }
664 
665  for (size_t i = 0; i < in_args.size (); ++i)
666  {
667  llvm::Value *arg = in_args[i];
668  jit_type::convert_fn convert = args[i]->pack (call_conv);
669  if (convert)
670  arg = convert (builder, arg);
671 
672  if (args[i]->pointer_arg (call_conv))
673  {
674  llvm::Type *ty = args[i]->packed_type (call_conv);
675  llvm::Value *alloca = pre_builder.CreateAlloca (ty);
676  builder.CreateStore (arg, alloca);
677  arg = alloca;
678  }
679 
680  llvm_args.push_back (arg);
681  }
682 
683  llvm::CallInst *callinst = builder.CreateCall (llvm_function, llvm_args);
684  llvm::Value *ret = callinst;
685 
686  if (sret ())
687  {
688 #if defined (CALLINST_ADDATTRIBUTE_ARG_IS_ATTRIBUTES)
689  llvm::AttrBuilder attr_builder;
690  attr_builder.addAttribute(llvm::Attributes::StructRet);
691  llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
692  callinst->addAttribute (1, attrs);
693 #else
694  callinst->addAttribute (1, llvm::Attribute::StructRet);
695 #endif
696  ret = builder.CreateLoad (sret_mem);
697  }
698 
699  if (mresult)
700  {
702  if (unpack)
703  ret = unpack (builder, ret);
704  }
705 
706  return ret;
707 }
708 
709 llvm::Value *
711 {
712  assert (idx < args.size ());
713 
714  // FIXME: We should be treating arguments like a list, not a vector.
715  // Shouldn't matter much for now, as the number of arguments shouldn't
716  // be much bigger than 4
717  llvm::Function::arg_iterator iter = llvm_function->arg_begin ();
718  if (sret ())
719  ++iter;
720 
721  for (size_t i = 0; i < idx; ++i, ++iter);
722 
723  if (args[idx]->pointer_arg (call_conv))
724  return builder.CreateLoad (iter);
725 
726  return iter;
727 }
728 
729 void
731  bool verify)
732 {
733  assert (! rval == ! mresult);
734 
735  if (rval)
736  {
738  if (convert)
739  rval = convert (builder, rval);
740 
741  if (sret ())
742  {
743  builder.CreateStore (rval, llvm_function->arg_begin ());
744  builder.CreateRetVoid ();
745  }
746  else
747  builder.CreateRet (rval);
748  }
749  else
750  builder.CreateRetVoid ();
751 
752  if (verify)
753  llvm::verifyFunction (*llvm_function);
754 }
755 
756 void
757 jit_function::do_add_mapping (llvm::ExecutionEngine *engine, void *fn)
758 {
759  assert (valid ());
760  engine->addGlobalMapping (llvm_function, fn);
761 }
762 
763 std::ostream&
764 operator<< (std::ostream& os, const jit_function& fn)
765 {
766  llvm::Function *lfn = fn.to_llvm ();
767  os << "jit_function: cc=" << fn.call_conv;
768  llvm::raw_os_ostream llvm_out (os);
769  lfn->print (llvm_out);
770  llvm_out.flush ();
771  return os;
772 }
773 
774 // -------------------- jit_operation --------------------
776 {
777  for (generated_map::iterator iter = generated.begin ();
778  iter != generated.end (); ++iter)
779  {
780  delete iter->first;
781  delete iter->second;
782  }
783 }
784 
785 void
787  const std::vector<jit_type*>& args)
788 {
789  if (args.size () >= overloads.size ())
790  overloads.resize (args.size () + 1);
791 
792  Array<jit_function>& over = overloads[args.size ()];
793  dim_vector dv (over.dims ());
794  Array<octave_idx_type> idx = to_idx (args);
795  bool must_resize = false;
796 
797  if (dv.length () != idx.numel ())
798  {
799  dv.resize (idx.numel ());
800  must_resize = true;
801  }
802 
803  for (octave_idx_type i = 0; i < dv.length (); ++i)
804  if (dv(i) <= idx(i))
805  {
806  must_resize = true;
807  dv(i) = idx(i) + 1;
808  }
809 
810  if (must_resize)
811  over.resize (dv);
812 
813  over(idx) = func;
814 }
815 
816 const jit_function&
817 jit_operation::overload (const std::vector<jit_type*>& types) const
818 {
819  static jit_function null_overload;
820  for (size_t i = 0; i < types.size (); ++i)
821  if (! types[i])
822  return null_overload;
823 
824  if (types.size () >= overloads.size ())
825  return do_generate (types);
826 
827  const Array<jit_function>& over = overloads[types.size ()];
828  dim_vector dv (over.dims ());
829  Array<octave_idx_type> idx = to_idx (types);
830  for (octave_idx_type i = 0; i < dv.length (); ++i)
831  if (idx(i) >= dv(i))
832  return do_generate (types);
833 
834  const jit_function& ret = over(idx);
835  if (! ret.valid ())
836  return do_generate (types);
837 
838  return ret;
839 }
840 
842 jit_operation::to_idx (const std::vector<jit_type*>& types) const
843 {
844  octave_idx_type numel = types.size ();
845  numel = std::max (numel, static_cast<octave_idx_type>(2));
846 
847  Array<octave_idx_type> idx (dim_vector (1, numel));
848  for (octave_idx_type i = 0; i < static_cast<octave_idx_type> (types.size ());
849  ++i)
850  idx(i) = types[i]->type_id ();
851 
852  if (types.size () == 0)
853  idx(0) = idx(1) = 0;
854  if (types.size () == 1)
855  {
856  idx(1) = idx(0);
857  idx(0) = 0;
858  }
859 
860  return idx;
861 }
862 
863 const jit_function&
865 {
866  static jit_function null_overload;
867  generated_map::const_iterator find = generated.find (&types);
868  if (find != generated.end ())
869  {
870  if (find->second)
871  return *find->second;
872  else
873  return null_overload;
874  }
875 
876  jit_function *ret = generate (types);
877  generated[new signature_vec (types)] = ret;
878  return ret ? *ret : null_overload;
879 }
880 
881 jit_function *
883 {
884  return 0;
885 }
886 
887 bool
889  const signature_vec *rhs) const
890 {
891  const signature_vec& l = *lhs;
892  const signature_vec& r = *rhs;
893 
894  if (l.size () < r.size ())
895  return true;
896  else if (l.size () > r.size ())
897  return false;
898 
899  for (size_t i = 0; i < l.size (); ++i)
900  {
901  if (l[i]->type_id () < r[i]->type_id ())
902  return true;
903  else if (l[i]->type_id () > r[i]->type_id ())
904  return false;
905  }
906 
907  return false;
908 }
909 
910 // -------------------- jit_index_operation --------------------
911 jit_function *
913 {
914  if (types.size () > 2 && types[0] == jit_typeinfo::get_matrix ())
915  {
916  // indexing a matrix with scalars
918  for (size_t i = 1; i < types.size (); ++i)
919  if (types[i] != scalar)
920  return 0;
921 
922  return generate_matrix (types);
923  }
924 
925  return 0;
926 }
927 
928 llvm::Value *
930  const jit_function &fn, size_t start_idx,
931  size_t end_idx) const
932 {
933  size_t n = end_idx - start_idx;
934  llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
935  llvm::ArrayType *array_t = llvm::ArrayType::get (scalar_t, n);
936  llvm::Value *array = llvm::UndefValue::get (array_t);
937  for (size_t i = start_idx; i < end_idx; ++i)
938  {
939  llvm::Value *idx = fn.argument (builder, i);
940  array = builder.CreateInsertValue (array, idx, i - start_idx);
941  }
942 
943  llvm::Value *array_mem = builder.CreateAlloca (array_t);
944  builder.CreateStore (array, array_mem);
945  return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ());
946 }
947 
948 // -------------------- jit_paren_subsref --------------------
949 jit_function *
951 {
952  std::stringstream ss;
953  ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1);
954 
957  ss.str (), scalar, types);
958  fn->mark_can_error ();
959  llvm::BasicBlock *body = fn->new_block ();
960  llvm::IRBuilder<> builder (body);
961 
962  llvm::Value *array = create_arg_array (builder, *fn, 1, types.size ());
963  jit_type *index = jit_typeinfo::get_index ();
964  llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (),
965  types.size () - 1);
966  llvm::Value *mat = fn->argument (builder, 0);
967  llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem);
968  fn->do_return (builder, ret);
969  return fn;
970 }
971 
972 void
974 {
975  std::vector<jit_type *> types (3);
976  types[0] = jit_typeinfo::get_matrix ();
977  types[1] = jit_typeinfo::get_scalar_ptr ();
978  types[2] = jit_typeinfo::get_index ();
979 
981  paren_scalar = jit_function (module, jit_convention::external,
982  "octave_jit_paren_scalar", scalar, types);
983  paren_scalar.add_mapping (engine, &octave_jit_paren_scalar);
984  paren_scalar.mark_can_error ();
985 }
986 
987 // -------------------- jit_paren_subsasgn --------------------
988 jit_function *
990 {
991  std::stringstream ss;
992  ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2);
993 
996  ss.str (), matrix, types);
997  fn->mark_can_error ();
998  llvm::BasicBlock *body = fn->new_block ();
999  llvm::IRBuilder<> builder (body);
1000 
1001  llvm::Value *array = create_arg_array (builder, *fn, 1, types.size () - 1);
1002  jit_type *index = jit_typeinfo::get_index ();
1003  llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (),
1004  types.size () - 2);
1005 
1006  llvm::Value *mat = fn->argument (builder, 0);
1007  llvm::Value *value = fn->argument (builder, types.size () - 1);
1008  llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem, value);
1009  fn->do_return (builder, ret);
1010  return fn;
1011 }
1012 
1013 void
1015 {
1016  if (paren_scalar.valid ())
1017  return;
1018 
1020  std::vector<jit_type *> types (4);
1021  types[0] = matrix;
1022  types[1] = jit_typeinfo::get_scalar_ptr ();
1023  types[2] = jit_typeinfo::get_index ();
1024  types[3] = jit_typeinfo::get_scalar ();
1025 
1026  paren_scalar = jit_function (module, jit_convention::external,
1027  "octave_jit_paren_scalar", matrix, types);
1028  paren_scalar.add_mapping (engine, &octave_jit_paren_scalar_subsasgn);
1029  paren_scalar.mark_can_error ();
1030 }
1031 
1032 // -------------------- jit_typeinfo --------------------
1033 void
1034 jit_typeinfo::initialize (llvm::Module *m, llvm::ExecutionEngine *e)
1035 {
1036  new jit_typeinfo (m, e);
1037 }
1038 
1039 // wrap function names to simplify jit_typeinfo::create_external
1040 #define JIT_FN(fn) engine, &fn, #fn
1041 
1042 jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e)
1043  : module (m), engine (e), next_id (0),
1044  builder (*new llvm::IRBuilderD (context))
1045 {
1046  instance = this;
1047 
1048  // FIXME: We should be registering types like in octave_value_typeinfo
1049  llvm::Type *any_t = llvm::StructType::create (context, "octave_base_value");
1050  any_t = any_t->getPointerTo ();
1051 
1052  llvm::Type *scalar_t = llvm::Type::getDoubleTy (context);
1053  llvm::Type *bool_t = llvm::Type::getInt1Ty (context);
1054  llvm::Type *string_t = llvm::Type::getInt8Ty (context);
1055  string_t = string_t->getPointerTo ();
1056  llvm::Type *index_t = llvm::Type::getIntNTy (context,
1057  sizeof(octave_idx_type) * 8);
1058 
1059  llvm::StructType *range_t = llvm::StructType::create (context, "range");
1060  std::vector<llvm::Type *> range_contents (4, scalar_t);
1061  range_contents[3] = index_t;
1062  range_t->setBody (range_contents);
1063 
1064  llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8);
1065 
1066  llvm::StructType *matrix_t = llvm::StructType::create (context, "matrix");
1067  llvm::Type *matrix_contents[5];
1068  matrix_contents[0] = refcount_t->getPointerTo ();
1069  matrix_contents[1] = scalar_t->getPointerTo ();
1070  matrix_contents[2] = index_t;
1071  matrix_contents[3] = index_t->getPointerTo ();
1072  matrix_contents[4] = string_t;
1073  matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5));
1074 
1075  llvm::Type *complex_t = llvm::ArrayType::get (scalar_t, 2);
1076 
1077  // complex_ret is what is passed to C functions in order to get calling
1078  // convention right
1079  llvm::Type *cmplx_inner_cont[] = {scalar_t, scalar_t};
1080  llvm::StructType *cmplx_inner = llvm::StructType::create (cmplx_inner_cont);
1081 
1082  complex_ret = llvm::StructType::create (context, "complex_ret");
1083  {
1084  llvm::Type *contents[] = {cmplx_inner};
1085  complex_ret->setBody (contents);
1086  }
1087 
1088  // create types
1089  any = new_type ("any", 0, any_t);
1090  matrix = new_type ("matrix", any, matrix_t);
1091  complex = new_type ("complex", any, complex_t);
1092  scalar = new_type ("scalar", complex, scalar_t);
1093  scalar_ptr = new_type ("scalar_ptr", 0, scalar_t->getPointerTo ());
1094  any_ptr = new_type ("any_ptr", 0, any_t->getPointerTo ());
1095  range = new_type ("range", any, range_t);
1096  string = new_type ("string", any, string_t);
1097  boolean = new_type ("bool", any, bool_t);
1098  index = new_type ("index", any, index_t);
1099 
1100  create_int (8);
1101  create_int (16);
1102  create_int (32);
1103  create_int (64);
1104 
1105  casts.resize (next_id + 1);
1106  identities.resize (next_id + 1);
1107 
1108  // specify calling conventions
1109  // FIXME: We should detect architecture and do something sane based on that
1110  // here we assume x86 or x86_64
1113 
1114  range->mark_sret (jit_convention::external);
1115  range->mark_pointer_arg (jit_convention::external);
1116 
1120 
1121  if (sizeof (void *) == 4)
1123 
1126 
1127  // bind global variables
1128  lerror_state = new llvm::GlobalVariable (*module, bool_t, false,
1129  llvm::GlobalValue::ExternalLinkage,
1130  0, "error_state");
1131  engine->addGlobalMapping (lerror_state,
1132  reinterpret_cast<void *> (&error_state));
1133 
1134  // sig_atomic_type is going to be some sort of integer
1135  sig_atomic_type = llvm::Type::getIntNTy (context, sizeof(sig_atomic_t) * 8);
1137  = new llvm::GlobalVariable (*module, sig_atomic_type, false,
1138  llvm::GlobalValue::ExternalLinkage, 0,
1139  "octave_interrupt_state");
1140  engine->addGlobalMapping (loctave_interrupt_state,
1141  reinterpret_cast<void *> (&octave_interrupt_state));
1142 
1143  // generic call function
1144  {
1145  jit_type *int_t = intN (sizeof (octave_builtin::fcn) * 8);
1146  any_call = create_external (JIT_FN (octave_jit_call), any, int_t, int_t,
1147  any_ptr, int_t);
1148  }
1149 
1150  // any with anything is an any op
1151  jit_function fn;
1152  jit_type *binary_op_type = intN (sizeof (octave_value::binary_op) * 8);
1153  llvm::Type *llvm_bo_type = binary_op_type->to_llvm ();
1155  any, binary_op_type, any, any);
1156  any_binary.mark_can_error ();
1158  for (size_t i = 0; i < octave_value::num_binary_ops; ++i)
1159  {
1162  binary_ops[i].stash_name ("binary" + op_name);
1163  }
1164 
1166  for (size_t i = 0; i < octave_value::num_unary_ops; ++i)
1167  {
1168  octave_value::unary_op op = static_cast<octave_value::unary_op> (i);
1170  unary_ops[i].stash_name ("unary" + op_name);
1171  }
1172 
1173  for (int op = 0; op < octave_value::num_binary_ops; ++op)
1174  {
1175  llvm::Twine fn_name ("octave_jit_binary_any_any_");
1176  fn_name = fn_name + llvm::Twine (op);
1177 
1178  fn = create_internal (fn_name, any, any, any);
1179  fn.mark_can_error ();
1180  llvm::BasicBlock *block = fn.new_block ();
1181  builder.SetInsertPoint (block);
1182  llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op,
1183  std::numeric_limits<octave_value::binary_op>::is_signed);
1184  llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int);
1185  llvm::Value *ret = any_binary.call (builder, op_as_llvm,
1186  fn.argument (builder, 0),
1187  fn.argument (builder, 1));
1188  fn.do_return (builder, ret);
1189  binary_ops[op].add_overload (fn);
1190  }
1191 
1192  // grab matrix
1194  grab_fn.add_overload (fn);
1195 
1198  grab_fn.add_overload (create_identity (any_ptr));
1199  grab_fn.add_overload (create_identity (boolean));
1202 
1203  // release any
1205  release_fn.add_overload (fn);
1206  release_fn.stash_name ("release");
1207 
1208  // release matrix
1210  release_fn.add_overload (fn);
1211 
1212  // destroy
1214  destroy_fn.stash_name ("destroy");
1219 
1220  // -------------------- scalar related operations --------------------
1221 
1222  // now for binary scalar operations
1223  add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd);
1224  add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub);
1225  add_binary_op (scalar, octave_value::op_mul, llvm::Instruction::FMul);
1226  add_binary_op (scalar, octave_value::op_el_mul, llvm::Instruction::FMul);
1227 
1228  add_binary_fcmp (scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT);
1229  add_binary_fcmp (scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE);
1230  add_binary_fcmp (scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ);
1231  add_binary_fcmp (scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE);
1232  add_binary_fcmp (scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT);
1233  add_binary_fcmp (scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE);
1234 
1236  gripe_div0.mark_can_error ();
1237 
1238  // divide is annoying because it might error
1239  fn = create_internal ("octave_jit_div_scalar_scalar", scalar, scalar, scalar);
1240  fn.mark_can_error ();
1241 
1242  llvm::BasicBlock *body = fn.new_block ();
1243  builder.SetInsertPoint (body);
1244  {
1245  llvm::BasicBlock *warn_block = fn.new_block ("warn");
1246  llvm::BasicBlock *normal_block = fn.new_block ("normal");
1247 
1248  llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
1249  llvm::Value *check = builder.CreateFCmpUEQ (zero, fn.argument (builder, 1));
1250  builder.CreateCondBr (check, warn_block, normal_block);
1251 
1252  builder.SetInsertPoint (warn_block);
1253  gripe_div0.call (builder);
1254  builder.CreateBr (normal_block);
1255 
1256  builder.SetInsertPoint (normal_block);
1257  llvm::Value *ret = builder.CreateFDiv (fn.argument (builder, 0),
1258  fn.argument (builder, 1));
1259  fn.do_return (builder, ret);
1260  }
1261  binary_ops[octave_value::op_div].add_overload (fn);
1262  binary_ops[octave_value::op_el_div].add_overload (fn);
1263 
1264  // ldiv is the same as div with the operators reversed
1265  fn = mirror_binary (fn);
1266  binary_ops[octave_value::op_ldiv].add_overload (fn);
1267  binary_ops[octave_value::op_el_ldiv].add_overload (fn);
1268 
1269  // In general, the result of scalar ^ scalar is a complex number. We might
1270  // be able to improve on this if we keep track of the range of values
1271  // variables can take on.
1273  scalar);
1274  binary_ops[octave_value::op_pow].add_overload (fn);
1275  binary_ops[octave_value::op_el_pow].add_overload (fn);
1276 
1277  // now for unary scalar operations
1278  // FIXME: Impelment not
1279  fn = create_internal ("octave_jit_++", scalar, scalar);
1280  body = fn.new_block ();
1281  builder.SetInsertPoint (body);
1282  {
1283  llvm::Value *one = llvm::ConstantFP::get (scalar_t, 1);
1284  llvm::Value *val = fn.argument (builder, 0);
1285  val = builder.CreateFAdd (val, one);
1286  fn.do_return (builder, val);
1287  }
1288  unary_ops[octave_value::op_incr].add_overload (fn);
1289 
1290  fn = create_internal ("octave_jit_--", scalar, scalar);
1291  body = fn.new_block ();
1292  builder.SetInsertPoint (body);
1293  {
1294  llvm::Value *one = llvm::ConstantFP::get (scalar_t, 1);
1295  llvm::Value *val = fn.argument (builder, 0);
1296  val = builder.CreateFSub (val, one);
1297  fn.do_return (builder, val);
1298  }
1299  unary_ops[octave_value::op_decr].add_overload (fn);
1300 
1301  fn = create_internal ("octave_jit_uminus", scalar, scalar);
1302  body = fn.new_block ();
1303  builder.SetInsertPoint (body);
1304  {
1305  llvm::Value *mone = llvm::ConstantFP::get (scalar_t, -1);
1306  llvm::Value *val = fn.argument (builder, 0);
1307  val = builder.CreateFMul (val, mone);
1308  fn.do_return (builder, val);
1309  }
1310  unary_ops[octave_value::op_uminus].add_overload (fn);
1311 
1312  fn = create_identity (scalar);
1313  unary_ops[octave_value::op_uplus].add_overload (fn);
1314  unary_ops[octave_value::op_transpose].add_overload (fn);
1315  unary_ops[octave_value::op_hermitian].add_overload (fn);
1316 
1317  // now for binary complex operations
1318  fn = create_internal ("octave_jit_+_complex_complex", complex, complex,
1319  complex);
1320  body = fn.new_block ();
1321  builder.SetInsertPoint (body);
1322  {
1323  llvm::Value *lhs = fn.argument (builder, 0);
1324  llvm::Value *rhs = fn.argument (builder, 1);
1325  llvm::Value *real = builder.CreateFAdd (complex_real (lhs),
1326  complex_real (rhs));
1327  llvm::Value *imag = builder.CreateFAdd (complex_imag (lhs),
1328  complex_imag (rhs));
1329  fn.do_return (builder, complex_new (real, imag));
1330  }
1331  binary_ops[octave_value::op_add].add_overload (fn);
1332 
1333  fn = create_internal ("octave_jit_-_complex_complex", complex, complex,
1334  complex);
1335  body = fn.new_block ();
1336  builder.SetInsertPoint (body);
1337  {
1338  llvm::Value *lhs = fn.argument (builder, 0);
1339  llvm::Value *rhs = fn.argument (builder, 1);
1340  llvm::Value *real = builder.CreateFSub (complex_real (lhs),
1341  complex_real (rhs));
1342  llvm::Value *imag = builder.CreateFSub (complex_imag (lhs),
1343  complex_imag (rhs));
1344  fn.do_return (builder, complex_new (real, imag));
1345  }
1346  binary_ops[octave_value::op_sub].add_overload (fn);
1347 
1349  complex, complex, complex);
1350  binary_ops[octave_value::op_mul].add_overload (fn);
1351  binary_ops[octave_value::op_el_mul].add_overload (fn);
1352 
1354  complex, complex, complex);
1355  complex_div.mark_can_error ();
1356  binary_ops[octave_value::op_div].add_overload (fn);
1357  binary_ops[octave_value::op_ldiv].add_overload (fn);
1358 
1360  complex, complex);
1361  binary_ops[octave_value::op_pow].add_overload (fn);
1362  binary_ops[octave_value::op_el_pow].add_overload (fn);
1363 
1364  fn = create_internal ("octave_jit_*_scalar_complex", complex, scalar,
1365  complex);
1366  jit_function mul_scalar_complex = fn;
1367  body = fn.new_block ();
1368  builder.SetInsertPoint (body);
1369  {
1370  llvm::BasicBlock *complex_mul = fn.new_block ("complex_mul");
1371  llvm::BasicBlock *scalar_mul = fn.new_block ("scalar_mul");
1372 
1373  llvm::Value *fzero = llvm::ConstantFP::get (scalar_t, 0);
1374  llvm::Value *lhs = fn.argument (builder, 0);
1375  llvm::Value *rhs = fn.argument (builder, 1);
1376 
1377  llvm::Value *cmp = builder.CreateFCmpUEQ (complex_imag (rhs), fzero);
1378  builder.CreateCondBr (cmp, scalar_mul, complex_mul);
1379 
1380  builder.SetInsertPoint (scalar_mul);
1381  llvm::Value *temp = complex_real (rhs);
1382  temp = builder.CreateFMul (lhs, temp);
1383  fn.do_return (builder, complex_new (temp, fzero), false);
1384 
1385  builder.SetInsertPoint (complex_mul);
1386  temp = complex_new (builder.CreateFMul (lhs, complex_real (rhs)),
1387  builder.CreateFMul (lhs, complex_imag (rhs)));
1388  fn.do_return (builder, temp);
1389  }
1390  binary_ops[octave_value::op_mul].add_overload (fn);
1391  binary_ops[octave_value::op_el_mul].add_overload (fn);
1392 
1393  fn = mirror_binary (mul_scalar_complex);
1394  binary_ops[octave_value::op_mul].add_overload (fn);
1395  binary_ops[octave_value::op_el_mul].add_overload (fn);
1396 
1397  fn = create_internal ("octave_jit_+_scalar_complex", complex, scalar,
1398  complex);
1399  body = fn.new_block ();
1400  builder.SetInsertPoint (body);
1401  {
1402  llvm::Value *lhs = fn.argument (builder, 0);
1403  llvm::Value *rhs = fn.argument (builder, 1);
1404  llvm::Value *real = builder.CreateFAdd (lhs, complex_real (rhs));
1405  fn.do_return (builder, complex_real (rhs, real));
1406  }
1407  binary_ops[octave_value::op_add].add_overload (fn);
1408 
1409  fn = mirror_binary (fn);
1410  binary_ops[octave_value::op_add].add_overload (fn);
1411 
1412  fn = create_internal ("octave_jit_-_complex_scalar", complex, complex,
1413  scalar);
1414  body = fn.new_block ();
1415  builder.SetInsertPoint (body);
1416  {
1417  llvm::Value *lhs = fn.argument (builder, 0);
1418  llvm::Value *rhs = fn.argument (builder, 1);
1419  llvm::Value *real = builder.CreateFSub (complex_real (lhs), rhs);
1420  fn.do_return (builder, complex_real (lhs, real));
1421  }
1422  binary_ops[octave_value::op_sub].add_overload (fn);
1423 
1424  fn = create_internal ("octave_jit_-_scalar_complex", complex, scalar,
1425  complex);
1426  body = fn.new_block ();
1427  builder.SetInsertPoint (body);
1428  {
1429  llvm::Value *lhs = fn.argument (builder, 0);
1430  llvm::Value *rhs = fn.argument (builder, 1);
1431  llvm::Value *real = builder.CreateFSub (lhs, complex_real (rhs));
1432  fn.do_return (builder, complex_real (rhs, real));
1433  }
1434  binary_ops[octave_value::op_sub].add_overload (fn);
1435 
1437  complex);
1438  binary_ops[octave_value::op_pow].add_overload (fn);
1439  binary_ops[octave_value::op_el_pow].add_overload (fn);
1440 
1442  complex, scalar);
1443  binary_ops[octave_value::op_pow].add_overload (fn);
1444  binary_ops[octave_value::op_el_pow].add_overload (fn);
1445 
1446  // now for binary index operators
1447  add_binary_op (index, octave_value::op_add, llvm::Instruction::Add);
1448 
1449  // and binary bool operators
1450  add_binary_op (boolean, octave_value::op_el_or, llvm::Instruction::Or);
1451  add_binary_op (boolean, octave_value::op_el_and, llvm::Instruction::And);
1452 
1453  // now for printing functions
1454  print_fn.stash_name ("print");
1455  add_print (any, reinterpret_cast<void *> (&octave_jit_print_any));
1456  add_print (scalar, reinterpret_cast<void *> (&octave_jit_print_scalar));
1457 
1458  // initialize for loop
1459  for_init_fn.stash_name ("for_init");
1460 
1461  fn = create_internal ("octave_jit_for_range_init", index, range);
1462  body = fn.new_block ();
1463  builder.SetInsertPoint (body);
1464  {
1465  llvm::Value *zero = llvm::ConstantInt::get (index_t, 0);
1466  fn.do_return (builder, zero);
1467  }
1469 
1470  // bounds check for for loop
1471  for_check_fn.stash_name ("for_check");
1472 
1473  fn = create_internal ("octave_jit_for_range_check", boolean, range, index);
1474  body = fn.new_block ();
1475  builder.SetInsertPoint (body);
1476  {
1477  llvm::Value *nelem
1478  = builder.CreateExtractValue (fn.argument (builder, 0), 3);
1479  llvm::Value *idx = fn.argument (builder, 1);
1480  llvm::Value *ret = builder.CreateICmpULT (idx, nelem);
1481  fn.do_return (builder, ret);
1482  }
1484 
1485  // index variabe for for loop
1486  for_index_fn.stash_name ("for_index");
1487 
1488  fn = create_internal ("octave_jit_for_range_idx", scalar, range, index);
1489  body = fn.new_block ();
1490  builder.SetInsertPoint (body);
1491  {
1492  llvm::Value *idx = fn.argument (builder, 1);
1493  llvm::Value *didx = builder.CreateSIToFP (idx, scalar_t);
1494  llvm::Value *rng = fn.argument (builder, 0);
1495  llvm::Value *base = builder.CreateExtractValue (rng, 0);
1496  llvm::Value *inc = builder.CreateExtractValue (rng, 2);
1497 
1498  llvm::Value *ret = builder.CreateFMul (didx, inc);
1499  ret = builder.CreateFAdd (base, ret);
1500  fn.do_return (builder, ret);
1501  }
1503 
1504  // logically true
1505  logically_true_fn.stash_name ("logically_true");
1506 
1507  jit_function gripe_nantl
1509  gripe_nantl.mark_can_error ();
1510 
1511  fn = create_internal ("octave_jit_logically_true_scalar", boolean, scalar);
1512  fn.mark_can_error ();
1513 
1514  body = fn.new_block ();
1515  builder.SetInsertPoint (body);
1516  {
1517  llvm::BasicBlock *error_block = fn.new_block ("error");
1518  llvm::BasicBlock *normal_block = fn.new_block ("normal");
1519 
1520  llvm::Value *check = builder.CreateFCmpUNE (fn.argument (builder, 0),
1521  fn.argument (builder, 0));
1522  builder.CreateCondBr (check, error_block, normal_block);
1523 
1524  builder.SetInsertPoint (error_block);
1525  gripe_nantl.call (builder);
1526  builder.CreateBr (normal_block);
1527  builder.SetInsertPoint (normal_block);
1528 
1529  llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
1530  llvm::Value *ret = builder.CreateFCmpONE (fn.argument (builder, 0), zero);
1531  fn.do_return (builder, ret);
1532  }
1534 
1535  // logically_true boolean
1536  fn = create_identity (boolean);
1538 
1539  // make_range
1540  // FIXME: May be benificial to implement all in LLVM
1541  make_range_fn.stash_name ("make_range");
1542  jit_function compute_nelem
1544  index, scalar, scalar, scalar);
1545 
1546  fn = create_internal ("octave_jit_make_range", range, scalar, scalar, scalar);
1547  body = fn.new_block ();
1548  builder.SetInsertPoint (body);
1549  {
1550  llvm::Value *base = fn.argument (builder, 0);
1551  llvm::Value *limit = fn.argument (builder, 1);
1552  llvm::Value *inc = fn.argument (builder, 2);
1553  llvm::Value *nelem = compute_nelem.call (builder, base, limit, inc);
1554 
1555  llvm::Value *dzero = llvm::ConstantFP::get (scalar_t, 0);
1556  llvm::Value *izero = llvm::ConstantInt::get (index_t, 0);
1557  llvm::Value *rng = llvm::ConstantStruct::get (range_t, dzero, dzero, dzero,
1558  izero, NULL);
1559  rng = builder.CreateInsertValue (rng, base, 0);
1560  rng = builder.CreateInsertValue (rng, limit, 1);
1561  rng = builder.CreateInsertValue (rng, inc, 2);
1562  rng = builder.CreateInsertValue (rng, nelem, 3);
1563  fn.do_return (builder, rng);
1564  }
1566 
1567  // paren_subsref
1568  jit_type *jit_int = intN (sizeof (int) * 8);
1569  llvm::Type *int_t = jit_int->to_llvm ();
1570  jit_function ginvalid_index
1573  0, jit_int, jit_int, index,
1574  index);
1575 
1576  fn = create_internal ("()subsref", scalar, matrix, scalar);
1577  fn.mark_can_error ();
1578 
1579  body = fn.new_block ();
1580  builder.SetInsertPoint (body);
1581  {
1582  llvm::Value *one_idx = llvm::ConstantInt::get (index_t, 1);
1583  llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
1584 
1585  llvm::Value *undef = llvm::UndefValue::get (scalar_t);
1586  llvm::Value *mat = fn.argument (builder, 0);
1587  llvm::Value *idx = fn.argument (builder, 1);
1588 
1589  // convert index to scalar to integer, and check index >= 1
1590  llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t);
1591  llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t);
1592  llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx);
1593  llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one_idx);
1594  llvm::Value *cond = builder.CreateOr (cond0, cond1);
1595 
1596  llvm::BasicBlock *done = fn.new_block ("done");
1597  llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
1598  llvm::BasicBlock *normal = fn.new_block ("normal", done);
1599  builder.CreateCondBr (cond, conv_error, normal);
1600 
1601  builder.SetInsertPoint (conv_error);
1602  ginvalid_index.call (builder);
1603  builder.CreateBr (done);
1604 
1605  builder.SetInsertPoint (normal);
1606  llvm::Value *len
1607  = builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (2));
1608  cond = builder.CreateICmpSGT (int_idx, len);
1609 
1610  llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
1611  llvm::BasicBlock *success = fn.new_block ("success", done);
1612  builder.CreateCondBr (cond, bounds_error, success);
1613 
1614  builder.SetInsertPoint (bounds_error);
1615  gindex_range.call (builder, one_int, one_int, int_idx, len);
1616  builder.CreateBr (done);
1617 
1618  builder.SetInsertPoint (success);
1619  llvm::Value *data = builder.CreateExtractValue (mat,
1620  llvm::ArrayRef<unsigned> (1));
1621  llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx);
1622  llvm::Value *ret = builder.CreateLoad (gep);
1623  builder.CreateBr (done);
1624 
1625  builder.SetInsertPoint (done);
1626 
1627  llvm::PHINode *merge = llvm::PHINode::Create (scalar_t, 3);
1628  builder.Insert (merge);
1629  merge->addIncoming (undef, conv_error);
1630  merge->addIncoming (undef, bounds_error);
1631  merge->addIncoming (ret, success);
1632  fn.do_return (builder, merge);
1633  }
1635 
1636  // paren subsasgn
1637  paren_subsasgn_fn.stash_name ("()subsasgn");
1638 
1639  jit_function resize_paren_subsasgn
1641  index, scalar);
1642 
1643  fn = create_internal ("octave_jit_paren_subsasgn", matrix, matrix, scalar,
1644  scalar);
1645  fn.mark_can_error ();
1646  body = fn.new_block ();
1647  builder.SetInsertPoint (body);
1648  {
1649  llvm::Value *one_idx = llvm::ConstantInt::get (index_t, 1);
1650  llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
1651 
1652  llvm::Value *mat = fn.argument (builder, 0);
1653  llvm::Value *idx = fn.argument (builder, 1);
1654  llvm::Value *value = fn.argument (builder, 2);
1655 
1656  llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t);
1657  llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t);
1658  llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx);
1659  llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one_idx);
1660  llvm::Value *cond = builder.CreateOr (cond0, cond1);
1661 
1662  llvm::BasicBlock *done = fn.new_block ("done");
1663 
1664  llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
1665  llvm::BasicBlock *normal = fn.new_block ("normal", done);
1666  builder.CreateCondBr (cond, conv_error, normal);
1667  builder.SetInsertPoint (conv_error);
1668  ginvalid_index.call (builder);
1669  builder.CreateBr (done);
1670 
1671  builder.SetInsertPoint (normal);
1672  llvm::Value *len = builder.CreateExtractValue (mat, 2);
1673  cond0 = builder.CreateICmpSGT (int_idx, len);
1674 
1675  llvm::Value *rcount = builder.CreateExtractValue (mat, 0);
1676  rcount = builder.CreateLoad (rcount);
1677  cond1 = builder.CreateICmpSGT (rcount, one_int);
1678  cond = builder.CreateOr (cond0, cond1);
1679 
1680  llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
1681  llvm::BasicBlock *success = fn.new_block ("success", done);
1682  builder.CreateCondBr (cond, bounds_error, success);
1683 
1684  // resize on out of bounds access
1685  builder.SetInsertPoint (bounds_error);
1686  llvm::Value *resize_result = resize_paren_subsasgn.call (builder, mat,
1687  int_idx, value);
1688  builder.CreateBr (done);
1689 
1690  builder.SetInsertPoint (success);
1691  llvm::Value *data
1692  = builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (1));
1693  llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx);
1694  builder.CreateStore (value, gep);
1695  builder.CreateBr (done);
1696 
1697  builder.SetInsertPoint (done);
1698 
1699  llvm::PHINode *merge = llvm::PHINode::Create (matrix_t, 3);
1700  builder.Insert (merge);
1701  merge->addIncoming (mat, conv_error);
1702  merge->addIncoming (resize_result, bounds_error);
1703  merge->addIncoming (mat, success);
1704  fn.do_return (builder, merge);
1705  }
1707 
1709  matrix, range, scalar);
1710  fn.mark_can_error ();
1712 
1713  end1_fn.stash_name ("end1");
1714  fn = create_internal ("octave_jit_end1_matrix", scalar, matrix, index, index);
1715  body = fn.new_block ();
1716  builder.SetInsertPoint (body);
1717  {
1718  llvm::Value *mat = fn.argument (builder, 0);
1719  llvm::Value *ret = builder.CreateExtractValue (mat, 2);
1720  fn.do_return (builder, builder.CreateSIToFP (ret, scalar_t));
1721  }
1722  end1_fn.add_overload (fn);
1723 
1724  end_fn.stash_name ("end");
1726  index);
1727  end_fn.add_overload (fn);
1728 
1729  // -------------------- create_undef --------------------
1730  create_undef_fn.stash_name ("create_undef");
1733 
1734  casts[any->type_id ()].stash_name ("(any)");
1735  casts[scalar->type_id ()].stash_name ("(scalar)");
1736  casts[complex->type_id ()].stash_name ("(complex)");
1737  casts[matrix->type_id ()].stash_name ("(matrix)");
1738  casts[range->type_id ()].stash_name ("(range)");
1739 
1740  // cast any <- matrix
1742  casts[any->type_id ()].add_overload (fn);
1743 
1744  // cast matrix <- any
1746  casts[matrix->type_id ()].add_overload (fn);
1747 
1748  // cast any <- range
1750  casts[any->type_id ()].add_overload (fn);
1751 
1752  // cast range <- any
1754  casts[range->type_id ()].add_overload (fn);
1755 
1756  // cast any <- scalar
1758  casts[any->type_id ()].add_overload (fn);
1759 
1760  // cast scalar <- any
1762  casts[scalar->type_id ()].add_overload (fn);
1763 
1764  // cast any <- complex
1766  casts[any->type_id ()].add_overload (fn);
1767 
1768  // cast complex <- any
1770  casts[complex->type_id ()].add_overload (fn);
1771 
1772  // cast complex <- scalar
1773  fn = create_internal ("octave_jit_cast_complex_scalar", complex, scalar);
1774  body = fn.new_block ();
1775  builder.SetInsertPoint (body);
1776  {
1777  llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0);
1778  fn.do_return (builder, complex_new (fn.argument (builder, 0), zero));
1779  }
1780  casts[complex->type_id ()].add_overload (fn);
1781 
1782  // cast scalar <- complex
1783  fn = create_internal ("octave_jit_cast_scalar_complex", scalar, complex);
1784  body = fn.new_block ();
1785  builder.SetInsertPoint (body);
1786  fn.do_return (builder, complex_real (fn.argument (builder, 0)));
1787  casts[scalar->type_id ()].add_overload (fn);
1788 
1789  // cast any <- any
1790  fn = create_identity (any);
1791  casts[any->type_id ()].add_overload (fn);
1792 
1793  // cast scalar <- scalar
1794  fn = create_identity (scalar);
1795  casts[scalar->type_id ()].add_overload (fn);
1796 
1797  // cast complex <- complex
1798  fn = create_identity (complex);
1799  casts[complex->type_id ()].add_overload (fn);
1800 
1801  // -------------------- builtin functions --------------------
1802  add_builtin ("#unknown_function");
1803  unknown_function = builtins["#unknown_function"];
1804 
1805  add_builtin ("sin");
1806  register_intrinsic ("sin", llvm::Intrinsic::sin, scalar, scalar);
1807  register_generic ("sin", matrix, matrix);
1808 
1809  add_builtin ("cos");
1810  register_intrinsic ("cos", llvm::Intrinsic::cos, scalar, scalar);
1811  register_generic ("cos", matrix, matrix);
1812 
1813  add_builtin ("exp");
1814  register_intrinsic ("exp", llvm::Intrinsic::exp, scalar, scalar);
1815  register_generic ("exp", matrix, matrix);
1816 
1817  add_builtin ("balance");
1818  register_generic ("balance", matrix, matrix);
1819 
1820  add_builtin ("cond");
1821  register_generic ("cond", scalar, matrix);
1822 
1823  add_builtin ("det");
1824  register_generic ("det", scalar, matrix);
1825 
1826  add_builtin ("norm");
1827  register_generic ("norm", scalar, matrix);
1828 
1829  add_builtin ("rand");
1830  register_generic ("rand", matrix, scalar);
1831  register_generic ("rand", matrix, std::vector<jit_type *> (2, scalar));
1832 
1833  add_builtin ("magic");
1834  register_generic ("magic", matrix, scalar);
1835  register_generic ("magic", matrix, std::vector<jit_type *> (2, scalar));
1836 
1837  add_builtin ("eye");
1838  register_generic ("eye", matrix, scalar);
1839  register_generic ("eye", matrix, std::vector<jit_type *> (2, scalar));
1840 
1841  add_builtin ("mod");
1842  register_generic ("mod", scalar, std::vector<jit_type *> (2, scalar));
1843 
1844  casts.resize (next_id + 1);
1845  jit_function any_id = create_identity (any);
1847  any, any);
1848  jit_function release_any = get_release (any);
1849  std::vector<jit_type *> args;
1850  args.resize (1);
1851 
1852  for (std::map<std::string, jit_type *>::iterator iter = builtins.begin ();
1853  iter != builtins.end (); ++iter)
1854  {
1855  jit_type *btype = iter->second;
1856  args[0] = btype;
1857 
1858  grab_fn.add_overload (jit_function (grab_any, btype, args));
1859  release_fn.add_overload (jit_function (release_any, 0, args));
1860  casts[any->type_id ()].add_overload (jit_function (any_id, any, args));
1861 
1862  args[0] = any;
1863  casts[btype->type_id ()].add_overload (jit_function (any_id, btype,
1864  args));
1865  }
1866 }
1867 
1868 const jit_function&
1870 {
1871  jit_const_index *ccount = dynamic_cast<jit_const_index *> (count);
1872  if (ccount && ccount->value () == 1)
1873  return end1_fn.overload (value->type (), idx->type (), count->type ());
1874 
1875  return end_fn.overload (value->type (), idx->type (), count->type ());
1876 }
1877 
1878 jit_type*
1880  llvm::Type *llvm_type, bool skip_paren)
1881 {
1882  jit_type *ret = new jit_type (name, parent, llvm_type, skip_paren, next_id++);
1883  id_to_type.push_back (ret);
1884  return ret;
1885 }
1886 
1887 void
1889 {
1890  std::stringstream name;
1891  name << "octave_jit_print_" << ty->name ();
1892  jit_function fn = create_external (engine, fptr, name.str (),
1893  0, intN (8), ty);
1894  print_fn.add_overload (fn);
1895 }
1896 
1897 // FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp
1898 void
1899 jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op)
1900 {
1901  std::stringstream fname;
1902  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
1903  fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op)
1904  << "_" << ty->name ();
1905 
1906  jit_function fn = create_internal (fname.str (), ty, ty, ty);
1907  llvm::BasicBlock *block = fn.new_block ();
1908  builder.SetInsertPoint (block);
1909  llvm::Instruction::BinaryOps temp
1910  = static_cast<llvm::Instruction::BinaryOps>(llvm_op);
1911 
1912  llvm::Value *ret = builder.CreateBinOp (temp, fn.argument (builder, 0),
1913  fn.argument (builder, 1));
1914  fn.do_return (builder, ret);
1915  binary_ops[op].add_overload (fn);
1916 }
1917 
1918 void
1920 {
1921  std::stringstream fname;
1922  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
1923  fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
1924  << "_" << ty->name ();
1925 
1926  jit_function fn = create_internal (fname.str (), boolean, ty, ty);
1927  llvm::BasicBlock *block = fn.new_block ();
1928  builder.SetInsertPoint (block);
1929  llvm::CmpInst::Predicate temp
1930  = static_cast<llvm::CmpInst::Predicate>(llvm_op);
1931  llvm::Value *ret = builder.CreateICmp (temp, fn.argument (builder, 0),
1932  fn.argument (builder, 1));
1933  fn.do_return (builder, ret);
1934  binary_ops[op].add_overload (fn);
1935 }
1936 
1937 void
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 (), boolean, ty, ty);
1946  llvm::BasicBlock *block = fn.new_block ();
1947  builder.SetInsertPoint (block);
1948  llvm::CmpInst::Predicate temp
1949  = static_cast<llvm::CmpInst::Predicate>(llvm_op);
1950  llvm::Value *ret = builder.CreateFCmp (temp, fn.argument (builder, 0),
1951  fn.argument (builder, 1));
1952  fn.do_return (builder, ret);
1953  binary_ops[op].add_overload (fn);
1954 }
1955 
1958  jit_type *ret,
1959  const std::vector<jit_type *>& args)
1960 {
1961  jit_function result (module, cc, name, ret, args);
1962  return result;
1963 }
1964 
1967 {
1968  size_t id = type->type_id ();
1969  if (id >= identities.size ())
1970  identities.resize (id + 1);
1971 
1972  if (! identities[id].valid ())
1973  {
1974  std::stringstream name;
1975  name << "id_" << type->name ();
1976 
1977  jit_function fn = create_internal (name.str (), type, type);
1978  llvm::BasicBlock *body = fn.new_block ();
1979  builder.SetInsertPoint (body);
1980  fn.do_return (builder, fn.argument (builder, 0));
1981  return identities[id] = fn;
1982  }
1983 
1984  return identities[id];
1985 }
1986 
1987 llvm::Value *
1989 {
1990  return abuilder.CreateLoad (lerror_state);
1991 }
1992 
1993 llvm::Value *
1995 {
1996  llvm::LoadInst *val = abuilder.CreateLoad (loctave_interrupt_state);
1997  val->setVolatile (true);
1998  return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0));
1999 }
2000 
2001 void
2003 {
2004  jit_type *btype = new_type (name, any, any->to_llvm (), true);
2005  builtins[name] = btype;
2006 
2007  octave_builtin *ov_builtin = find_builtin (name);
2008  if (ov_builtin)
2009  ov_builtin->stash_jit (*btype);
2010 }
2011 
2012 void
2014  jit_type *result,
2015  const std::vector<jit_type *>& args)
2016 {
2017  jit_type *builtin_type = builtins[name];
2018  size_t nargs = args.size ();
2019  llvm::SmallVector<llvm::Type *, 5> llvm_args (nargs);
2020  for (size_t i = 0; i < nargs; ++i)
2021  llvm_args[i] = args[i]->to_llvm ();
2022 
2023  llvm::Intrinsic::ID id = static_cast<llvm::Intrinsic::ID> (iid);
2024  llvm::Function *ifun = llvm::Intrinsic::getDeclaration (module, id,
2025  llvm_args);
2026  std::stringstream fn_name;
2027  fn_name << "octave_jit_" << name;
2028 
2029  std::vector<jit_type *> args1 (nargs + 1);
2030  args1[0] = builtin_type;
2031  std::copy (args.begin (), args.end (), args1.begin () + 1);
2032 
2033  // The first argument will be the Octave function, but we already know that
2034  // the function call is the equivalent of the intrinsic, so we ignore it and
2035  // call the intrinsic with the remaining arguments.
2036  jit_function fn = create_internal (fn_name.str (), result, args1);
2037  llvm::BasicBlock *body = fn.new_block ();
2038  builder.SetInsertPoint (body);
2039 
2040  llvm::SmallVector<llvm::Value *, 5> fargs (nargs);
2041  for (size_t i = 0; i < nargs; ++i)
2042  fargs[i] = fn.argument (builder, i + 1);
2043 
2044  llvm::Value *ret = builder.CreateCall (ifun, fargs);
2045  fn.do_return (builder, ret);
2047 }
2048 
2051 {
2052  // FIXME: Finalize what we want to store in octave_builtin, then add functions
2053  // to access these values in octave_value
2054  octave_value ov_builtin = symbol_table::find (name);
2055  return dynamic_cast<octave_builtin *> (ov_builtin.internal_rep ());
2056 }
2057 
2058 void
2060  const std::vector<jit_type *>& args)
2061 {
2062  octave_builtin *builtin = find_builtin (name);
2063  if (! builtin)
2064  return;
2065 
2066  std::vector<jit_type *> fn_args (args.size () + 1);
2067  fn_args[0] = builtins[name];
2068  std::copy (args.begin (), args.end (), fn_args.begin () + 1);
2069  jit_function fn = create_internal (name, result, fn_args);
2070  fn.mark_can_error ();
2071  llvm::BasicBlock *block = fn.new_block ();
2072  builder.SetInsertPoint (block);
2073  llvm::Type *any_t = any->to_llvm ();
2074  llvm::ArrayType *array_t = llvm::ArrayType::get (any_t, args.size ());
2075  llvm::Value *array = llvm::UndefValue::get (array_t);
2076  for (size_t i = 0; i < args.size (); ++i)
2077  {
2078  llvm::Value *arg = fn.argument (builder, i + 1);
2079  jit_function agrab = get_grab (args[i]);
2080  if (agrab.valid ())
2081  arg = agrab.call (builder, arg);
2082  jit_function acast = cast (any, args[i]);
2083  array = builder.CreateInsertValue (array, acast.call (builder, arg), i);
2084  }
2085 
2086  llvm::Value *array_mem = builder.CreateAlloca (array_t);
2087  builder.CreateStore (array, array_mem);
2088  array = builder.CreateBitCast (array_mem, any_t->getPointerTo ());
2089 
2090  jit_type *jintTy = intN (sizeof (octave_builtin::fcn) * 8);
2091  llvm::Type *intTy = jintTy->to_llvm ();
2092  size_t fcn_int = reinterpret_cast<size_t> (builtin->function ());
2093  llvm::Value *fcn = llvm::ConstantInt::get (intTy, fcn_int);
2094  llvm::Value *nargin = llvm::ConstantInt::get (intTy, args.size ());
2095  size_t result_int = reinterpret_cast<size_t> (result);
2096  llvm::Value *res_llvm = llvm::ConstantInt::get (intTy, result_int);
2097  llvm::Value *ret = any_call.call (builder, fcn, nargin, array, res_llvm);
2098 
2099  jit_function cast_result = cast (result, any);
2100  fn.do_return (builder, cast_result.call (builder, ret));
2102 }
2103 
2106 {
2107  jit_function ret = create_internal (fn.name () + "_reverse",
2108  fn.result (), fn.argument_type (1),
2109  fn.argument_type (0));
2110  if (fn.can_error ())
2111  ret.mark_can_error ();
2112 
2113  llvm::BasicBlock *body = ret.new_block ();
2114  builder.SetInsertPoint (body);
2115  llvm::Value *result = fn.call (builder, ret.argument (builder, 1),
2116  ret.argument (builder, 0));
2117  if (ret.result ())
2118  ret.do_return (builder, result);
2119  else
2120  ret.do_return (builder);
2121 
2122  return ret;
2123 }
2124 
2125 llvm::Value *
2127 {
2128  llvm::Type *complex_ret = instance->complex_ret;
2129  llvm::Value *real = bld.CreateExtractValue (cplx, 0);
2130  llvm::Value *imag = bld.CreateExtractValue (cplx, 1);
2131  llvm::Value *ret = llvm::UndefValue::get (complex_ret);
2132 
2133  unsigned int re_idx[] = {0, 0};
2134  unsigned int im_idx[] = {0, 1};
2135  ret = bld.CreateInsertValue (ret, real, re_idx);
2136  return bld.CreateInsertValue (ret, imag, im_idx);
2137 }
2138 
2139 llvm::Value *
2141 {
2142  unsigned int re_idx[] = {0, 0};
2143  unsigned int im_idx[] = {0, 1};
2144 
2145  llvm::Type *complex_t = get_complex ()->to_llvm ();
2146  llvm::Value *real = bld.CreateExtractValue (result, re_idx);
2147  llvm::Value *imag = bld.CreateExtractValue (result, im_idx);
2148  llvm::Value *ret = llvm::UndefValue::get (complex_t);
2149 
2150  ret = bld.CreateInsertValue (ret, real, 0);
2151  return bld.CreateInsertValue (ret, imag, 1);
2152 }
2153 
2154 llvm::Value *
2156 {
2157  return builder.CreateExtractValue (cx, 0);
2158 }
2159 
2160 llvm::Value *
2161 jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real)
2162 {
2163  return builder.CreateInsertValue (cx, real, 0);
2164 }
2165 
2166 llvm::Value *
2168 {
2169  return builder.CreateExtractValue (cx, 1);
2170 }
2171 
2172 llvm::Value *
2173 jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag)
2174 {
2175  return builder.CreateInsertValue (cx, imag, 1);
2176 }
2177 
2178 llvm::Value *
2179 jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag)
2180 {
2181  llvm::Value *ret = llvm::UndefValue::get (complex->to_llvm ());
2182  ret = complex_real (ret, real);
2183  return complex_imag (ret, imag);
2184 }
2185 
2186 void
2188 {
2189  std::stringstream tname;
2190  tname << "int" << nbits;
2191  ints[nbits] = new_type (tname.str (), any, llvm::Type::getIntNTy (context,
2192  nbits));
2193 }
2194 
2195 jit_type *
2196 jit_typeinfo::intN (size_t nbits) const
2197 {
2198  std::map<size_t, jit_type *>::const_iterator iter = ints.find (nbits);
2199  if (iter != ints.end ())
2200  return iter->second;
2201 
2202  throw jit_fail_exception ("No such integer type");
2203 }
2204 
2205 jit_type *
2207 {
2208  if (ov.is_function ())
2209  {
2210  // FIXME: This is ugly, we need to finalize how we want to do this, then
2211  // have octave_value fully support the needed functionality
2212  octave_builtin *builtin
2213  = dynamic_cast<octave_builtin *> (ov.internal_rep ());
2214  return builtin && builtin->to_jit () ? builtin->to_jit ()
2215  : unknown_function;
2216  }
2217 
2218  if (ov.is_range ())
2219  return get_range ();
2220 
2221  if (ov.is_double_type () && ! ov.is_complex_type ())
2222  {
2223  if (ov.is_real_scalar ())
2224  return get_scalar ();
2225 
2226  if (ov.is_matrix_type ())
2227  return get_matrix ();
2228  }
2229 
2230  if (ov.is_complex_scalar ())
2231  {
2232  Complex cv = ov.complex_value ();
2233 
2234  // We don't really represent complex values, instead we represent
2235  // complex_or_scalar. If the imag value is zero, we assume a scalar.
2236  if (cv.imag () != 0)
2237  return get_complex ();
2238  }
2239 
2240  return get_any ();
2241 }
2242 
2243 #endif
uint32_t id
Definition: graphics.cc:11587
jit_type * result(void) const
Definition: jit-typeinfo.h:295
void do_return(llvm::IRBuilderD &builder, llvm::Value *rval=0, bool verify=true)
octave_idx_type slice_len
Definition: jit-typeinfo.h:102
Array< octave_idx_type > to_idx(const signature_vec &types) const
void stash_jit(jit_type &type)
Definition: ov-builtin.cc:151
llvm::Module * module
Definition: jit-typeinfo.h:790
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:587
jit_type * unknown_function
Definition: jit-typeinfo.h:810
jit_type * complex
Definition: jit-typeinfo.h:809
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:43
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:251
const std::string & name(void) const
Definition: jit-typeinfo.h:143
fname
Definition: load-save.cc:754
llvm::Value * complex_imag(llvm::Value *cx)
llvm::Type * sig_atomic_type
Definition: jit-typeinfo.h:797
double octave_jit_cast_scalar_any(octave_base_value *obv)
octave_value_list(* fcn)(const octave_value_list &, int)
Definition: ov-builtin.h:47
jit_operation for_check_fn
Definition: jit-typeinfo.h:823
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:808
nd group nd example oindent but is performed more efficiently If only and it is a scalar
Definition: data.cc:5342
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:152
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
jit_paren_subsref paren_subsref_fn
Definition: jit-typeinfo.h:827
static std::string binary_op_as_string(binary_op)
Definition: ov.cc:175
bool is_function(void) const
Definition: ov.h:711
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
static void initialize(llvm::Module *m, llvm::ExecutionEngine *e)
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
virtual jit_function * generate(const signature_vec &types) const
jit_type * to_jit(void) const
Definition: ov-builtin.cc:145
octave_idx_type length(void) const
Definition: ovl.h:96
jit_block * parent(void) const
Definition: jit-ir.h:446
jit_block * mparent
Definition: jit-ir.h:482
bool mpointer_arg[jit_convention::length]
Definition: jit-typeinfo.h:208
virtual Range range_value(void) const
Definition: ov-base.cc:864
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:752
jit_matrix octave_jit_paren_subsasgn_matrix_range(jit_matrix *mat, jit_range *index, double value)
jit_type * scalar_ptr
Definition: jit-typeinfo.h:803
std::ostream & operator<<(std::ostream &os, const jit_range &rng)
llvm::Type * llvm_type
Definition: jit-typeinfo.h:202
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the then the first element defines the pivoting tolerance for the unsymmetric the values defined such that for full matrix
Definition: lu.cc:138
bool is_complex_scalar(void) const
Definition: ov.h:557
void resize(int n, int fill_value=0)
Definition: dim-vector.h:316
Definition: Range.h:33
bool sret(void) const
Definition: jit-typeinfo.h:289
jit_type * new_type(const std::string &name, jit_type *parent, llvm::Type *llvm_type, bool skip_paren=false)
binary_op
Definition: ov.h:89
Complex octave_jit_complex_div(Complex lhs, Complex rhs)
void err_index_out_of_range(int nd, int dim, octave_idx_type idx, octave_idx_type ext)
bool msret[jit_convention::length]
Definition: jit-typeinfo.h:207
static llvm::Value * pack_complex(llvm::IRBuilderD &bld, llvm::Value *cplx)
void err_invalid_index(const std::string &idx, octave_idx_type nd, octave_idx_type dim, const std::string &)
void error(const char *fmt,...)
Definition: error.cc:570
void set_packed_type(jit_convention::type cc, llvm::Type *ty)
Definition: jit-typeinfo.h:197
is greater than zero
Definition: load-path.cc:2339
jit_type * type(void) const
Definition: jit-ir.h:215
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:169
llvm::Type * mpacked_type[jit_convention::length]
Definition: jit-typeinfo.h:213
T * jit_slice_data(void) const
Definition: Array.h:846
jit_operation destroy_fn
Definition: jit-typeinfo.h:820
llvm::Value * complex_new(llvm::Value *real, llvm::Value *imag)
jit_type * mresult
Definition: jit-typeinfo.h:309
void add_overload(const jit_function &func)
Definition: jit-typeinfo.h:328
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:799
octave_idx_type nelem
Definition: jit-typeinfo.h:63
convert_fn pack(jit_convention::type cc)
Definition: jit-typeinfo.h:183
std::map< size_t, jit_type * > ints
Definition: jit-typeinfo.h:811
void erase(void)
jit_operation release_fn
Definition: jit-typeinfo.h:819
static llvm::IRBuilder builder(llvm::getGlobalContext())
static llvm::Type * get_scalar_llvm(void)
Definition: jit-typeinfo.h:452
void err_nan_to_logical_conversion(void)
i e
Definition: data.cc:2724
jit_type * range
Definition: jit-typeinfo.h:805
jit_type * boolean
Definition: jit-typeinfo.h:807
llvm::TerminatorInst * to_llvm(void) const
Definition: jit-ir.cc:701
double base
Definition: jit-typeinfo.h:60
void mark_pointer_arg(jit_convention::type cc)
Definition: jit-typeinfo.h:177
jit_range octave_jit_cast_range_any(octave_base_value *obv)
octave_value arg
Definition: pr-output.cc:3440
octave_function * fcn
Definition: ov-class.cc:1743
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:308
llvm::GlobalVariable * lerror_state
Definition: jit-typeinfo.h:794
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:812
bool swap
Definition: load-save.cc:725
JNIEnv void * args
Definition: ov-java.cc:67
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:679
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:439
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:602
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)
done
Definition: syscalls.cc:248
const jit_function & do_generate(const signature_vec &types) const
const jit_function & overload(const signature_vec &types) const
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
jit_operation print_fn
Definition: jit-typeinfo.h:821
bool pointer_arg(jit_convention::type cc) const
Definition: jit-typeinfo.h:175
int * jit_ref_count(void)
WARNING: Only call these functions from jit.
Definition: Array.h:844
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:841
void octave_jit_release_any(octave_base_value *obv)
size_t mid
Definition: jit-ir.h:481
virtual double double_value(bool=false) const
Definition: ov-base.cc:560
fcn function(void) const
Definition: ov-builtin.cc:157
U * slice_data
Definition: jit-typeinfo.h:101
bool is_real_scalar(void) const
Definition: ov.h:551
jit_type * matrix
Definition: jit-typeinfo.h:801
std::vector< jit_operation > binary_ops
Definition: jit-typeinfo.h:816
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:76
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
void octave_jit_print_matrix(jit_matrix *m)
then the function must return scalars which will be concatenated into the return array(s).If code
Definition: cellfun.cc:398
bool is_matrix_type(void) const
Definition: ov.h:676
void resize1(octave_idx_type n, const T &rfv)
Definition: Array.cc:915
jit_convention::type call_conv
Definition: jit-typeinfo.h:311
int nargin
Definition: graphics.cc:10115
llvm::StructType * complex_ret
Definition: jit-typeinfo.h:814
bool is_double_type(void) const
Definition: ov.h:624
jit_operation for_init_fn
Definition: jit-typeinfo.h:822
octave_idx_type numel(void) const
Definition: Range.h:85
std::vector< jit_operation > unary_ops
Definition: jit-typeinfo.h:817
virtual jit_function * generate_matrix(const signature_vec &types) const
int error_state
Definition: error.cc:106
jit_type * do_type_of(const octave_value &ov) const
bool is_complex_type(void) const
Definition: ov.h:670
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:1028
octave_int< T > pow(const octave_int< T > &a, const octave_int< T > &b)
jit_type * any_ptr
Definition: jit-typeinfo.h:804
jit_operation grab_fn
Definition: jit-typeinfo.h:818
bool can_error(void) const
Definition: jit-typeinfo.h:291
is false
Definition: cellfun.cc:398
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:297
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:58
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)
idx type
Definition: ov.cc:3129
void warn_divide_by_zero(void)
Definition: errwarn.cc:320
llvm::Module * module
Definition: jit-typeinfo.h:307
Definition: dMatrix.h:37
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
octave_idx_type * dimensions
Definition: jit-typeinfo.h:103
bool operator()(const signature_vec *lhs, const signature_vec *rhs) const
With real return the complex result
Definition: data.cc:3375
jit_operation logically_true_fn
Definition: jit-typeinfo.h:825
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)
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:112
T & xelem(octave_idx_type n)
Definition: Array.h:455
void update(void)
Definition: jit-typeinfo.h:80
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:800
convert_fn unpack(jit_convention::type cc)
Definition: jit-typeinfo.h:188
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:126
static OCTAVE_NORETURN void err_bad_result(void)
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
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:99
bool empty(void) const
Definition: ovl.h:98
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:826
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:713
T::size_type numel(const T &str)
Definition: oct-string.cc:61
#define octave_stdout
Definition: pager.h:146
jit_paren_subsasgn paren_subsasgn_fn
Definition: jit-typeinfo.h:828
octave::sys::time start
Definition: graphics.cc:11731
jit_type * ty
Definition: jit-ir.h:278
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)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
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 * >())
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
void initialize(llvm::Module *amodule, llvm::ExecutionEngine *aengine)
Definition: jit-typeinfo.h:388
double inc
Definition: jit-typeinfo.h:62
void register_intrinsic(const std::string &name, size_t id, jit_type *result, jit_type *arg0)
Definition: jit-typeinfo.h:742
Complex complex_value(bool frc_str_conv=false) const
Definition: ov.h:799
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:470
convert_fn munpack[jit_convention::length]
Definition: jit-typeinfo.h:211
llvm::Value *(* convert_fn)(llvm::IRBuilderD &, llvm::Value *)
Definition: jit-typeinfo.h:137
convert_fn mpack[jit_convention::length]
Definition: jit-typeinfo.h:210
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:1225
PASS_T value(void) const
Definition: jit-ir.h:522
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:824
jit_function any_call
Definition: jit-typeinfo.h:833
generated_map generated
Definition: jit-typeinfo.h:375
jit_operation end_fn
Definition: jit-typeinfo.h:830
bool is_undefined(void) const
Definition: ov.h:539
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:1133
void set_pack(jit_convention::type cc, convert_fn fn)
Definition: jit-typeinfo.h:185
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:142
int type_id(void) const
Definition: jit-typeinfo.h:146
virtual void do_initialize(void)
double limit
Definition: jit-typeinfo.h:61
static jit_typeinfo * instance
Definition: jit-typeinfo.h:788
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)
FloatComplex(* fptr)(const FloatComplex &, float, int, octave_idx_type &)
Definition: lo-specfun.cc:1724
jit_type * any
Definition: jit-typeinfo.h:800
void do_add_mapping(llvm::ExecutionEngine *engine, void *fn)
std::complex< double > Complex
Definition: oct-cmplx.h:31
const T * fortran_vec(void) const
Definition: Array.h:584
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:119
llvm::ExecutionEngine * engine
Definition: jit-typeinfo.h:791
octave_base_value * internal_rep(void) const
Definition: ov.h:1299
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:136
llvm::Type * to_llvm_arg(void) const
void release(void)
Definition: ov-base.h:807
virtual NDArray array_value(bool=false) const
Definition: ov-base.cc:590
llvm::Function * to_llvm(void) const
Definition: jit-typeinfo.h:286
jit_operation end1_fn
Definition: jit-typeinfo.h:829
double octave_jit_paren_scalar(jit_matrix *mat, double *indicies, octave_idx_type idx_count)
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
jit_type * scalar
Definition: jit-typeinfo.h:802
void mark_can_error(void)
Definition: jit-typeinfo.h:293
std::vector< jit_operation > casts
Definition: jit-typeinfo.h:836
jit_matrix octave_jit_cast_matrix_any(octave_base_value *obv)
octave_value & xelem(octave_idx_type i)
Definition: ovl.h:150
llvm::Type * packed_type(jit_convention::type cc)
Definition: jit-typeinfo.h:194
unary_op
Definition: ov.h:76
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
int length(void) const
Number of dimensions.
Definition: dim-vector.h:310
void set_unpack(jit_convention::type cc, convert_fn fn)
Definition: jit-typeinfo.h:190
std::vector< jit_function > identities
Definition: jit-typeinfo.h:839
llvm::Value * create_arg_array(llvm::IRBuilderD &builder, const jit_function &fn, size_t start_idx, size_t end_idx) const
dim_vector dv
Definition: sub2ind.cc:263
virtual void print_with_name(std::ostream &output_buf, const std::string &name, bool print_padding=true)
Definition: ov-base.cc:479
jit_typeinfo(llvm::Module *m, llvm::ExecutionEngine *e)
IRBuilder< true, ConstantFolder, IRBuilderDefaultInserter< true > > IRBuilderD
Definition: jit-util.h:74
std::string name(void) const
void octave_jit_release_matrix(jit_matrix *m)
T x_nint(T x)
Definition: lo-mappers.h:299
jit_operation create_undef_fn
Definition: jit-typeinfo.h:831
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
llvm::GlobalVariable * loctave_interrupt_state
Definition: jit-typeinfo.h:795
static jit_type * get_index(void)
Definition: jit-typeinfo.h:465
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:205
octave_value do_binary_op(octave_value::binary_op op, const octave_value &v1, const octave_value &v2)
Definition: ov.cc:2214
std::vector< Array< jit_function > > overloads
Definition: jit-typeinfo.h:377
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:1255
bool all_elements_are_ints() const