GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
jit-typeinfo.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2012-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // defines required by llvm
27 #define __STDC_LIMIT_MACROS
28 #define __STDC_CONSTANT_MACROS
29 
30 #if defined (HAVE_CONFIG_H)
31 # include "config.h"
32 #endif
33 
34 #if defined (HAVE_LLVM)
35 
36 #if defined (HAVE_LLVM_IR_VERIFIER_H)
37 # include <llvm/IR/Verifier.h>
38 #else
39 # include <llvm/Analysis/Verifier.h>
40 #endif
41 
42 #include <llvm/ExecutionEngine/ExecutionEngine.h>
43 
44 #if defined (HAVE_LLVM_IR_FUNCTION_H)
45 # include <llvm/IR/GlobalVariable.h>
46 # include <llvm/IR/LLVMContext.h>
47 # include <llvm/IR/Function.h>
48 # include <llvm/IR/Instructions.h>
49 # include <llvm/IR/Intrinsics.h>
50 #else
51 # include <llvm/GlobalVariable.h>
52 # include <llvm/LLVMContext.h>
53 # include <llvm/Function.h>
54 # include <llvm/Instructions.h>
55 # include <llvm/Intrinsics.h>
56 #endif
57 
58 #if defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
59 # include <llvm/Support/IRBuilder.h>
60 # elif defined(HAVE_LLVM_IR_IRBUILDER_H)
61 # include <llvm/IR/IRBuilder.h>
62 #else
63 # include <llvm/IRBuilder.h>
64 #endif
65 
66 #include <llvm/Support/raw_os_ostream.h>
67 
68 #include "jit-typeinfo.h"
69 #include "pt-jit.h"
70 #include "jit-ir.h"
71 #include "ov.h"
72 #include "ov-builtin.h"
73 #include "ov-complex.h"
74 #include "ov-scalar.h"
75 #include "pager.h"
76 #include "interpreter-private.h"
77 
78 namespace octave
79 {
80  static llvm::LLVMContext& context = tree_jit::llvm_context;
81 
82  std::ostream& jit_print (std::ostream& os, jit_type *atype)
83  {
84  if (! atype)
85  return os << "null";
86  return os << atype->name ();
87  }
88 
89  // function that jit code calls
90  extern "C" void
92  {
93  obv->print_with_name (octave_stdout, name, true);
94  }
95 
96  extern "C" void
97  octave_jit_print_scalar (const char *name, double value)
98  {
99  // FIXME: We should avoid allocating a new octave_scalar each time
100  octave_value ov (value);
102  }
103 
104  extern "C" octave_base_value*
106  octave_base_value *rhs)
107  {
108  octave_value olhs (lhs, true);
109  octave_value orhs (rhs, true);
110  octave_value result = do_binary_op (op, olhs, orhs);
111  octave_base_value *rep = result.internal_rep ();
112  rep->grab ();
113  return rep;
114  }
115 
116  extern "C" octave_idx_type
117  octave_jit_compute_nelem (double base, double limit, double inc)
118  {
119  Range rng = Range (base, limit, inc);
120  return rng.numel ();
121  }
122 
123  extern "C" void
125  {
126  obv->release ();
127  }
128 
129  extern "C" void
131  {
132  delete m->m_array;
133  }
134 
135  extern "C" octave_base_value *
137  {
138  obv->grab ();
139  return obv;
140  }
141 
142  extern "C" jit_matrix
144  {
145  return *m->m_array;
146  }
147 
148  extern "C" octave_base_value *
150  {
151  octave_value ret (*m->m_array);
152  octave_base_value *rep = ret.internal_rep ();
153  rep->grab ();
154  delete m->m_array;
155 
156  return rep;
157  }
158 
159  extern "C" jit_matrix
161  {
162  NDArray m = obv->array_value ();
163  obv->release ();
164  return m;
165  }
166 
167  extern "C" octave_base_value *
169  {
170  Range temp (*rng);
171  octave_value ret (temp);
172  octave_base_value *rep = ret.internal_rep ();
173  rep->grab ();
174 
175  return rep;
176  }
177  extern "C" jit_range
179  {
180 
181  jit_range r (obv->range_value ());
182  obv->release ();
183  return r;
184  }
185 
186  extern "C" double
188  {
189  double ret = obv->double_value ();
190  obv->release ();
191  return ret;
192  }
193 
194  extern "C" octave_base_value *
196  {
197  return new octave_scalar (value);
198  }
199 
200  extern "C" Complex
202  {
203  Complex ret = obv->complex_value ();
204  obv->release ();
205  return ret;
206  }
207 
208  extern "C" octave_base_value *
210  {
211  if (c.imag () == 0)
212  return new octave_scalar (c.real ());
213  else
214  return new octave_complex (c);
215  }
216 
217  extern "C" void
219  {
221  }
222 
223  extern "C" void
225  {
226  // FIXME: 0-argument form of err_invalid_index removed in
227  // cset dd6345fd8a97. Report -1 as the bad index for all
228  // occurrences.
229  err_invalid_index (static_cast<octave_idx_type> (-1));
230  }
231 
232  extern "C" void
233  octave_jit_gindex_range (int nd, int dim, octave_idx_type iext,
234  octave_idx_type ext)
235  {
236  err_index_out_of_range (nd, dim, iext, ext);
237  }
238 
239  extern "C" jit_matrix
241  double value)
242  {
243  NDArray *array = mat->m_array;
244  if (array->numel () < index)
245  array->resize1 (index);
246 
247  double *data = array->fortran_vec ();
248  data[index - 1] = value;
249 
250  mat->update ();
251  return *mat;
252  }
253 
254  static void
255  make_indices (double *indices, octave_idx_type idx_count,
256  Array<idx_vector>& result)
257  {
258  result.resize (dim_vector (1, idx_count));
259  for (octave_idx_type i = 0; i < idx_count; ++i)
260  result(i) = idx_vector (indices[i]);
261  }
262 
263  extern "C" double
264  octave_jit_paren_scalar (jit_matrix *mat, double *indices,
265  octave_idx_type idx_count)
266  {
267  // FIXME: Replace this with a more optimal version
268  Array<idx_vector> idx;
269  make_indices (indices, idx_count, idx);
270 
271  Array<double> ret = mat->m_array->index (idx);
272 
273  return ret.xelem (0);
274  }
275 
276  extern "C" jit_matrix
278  octave_idx_type idx_count, double value)
279  {
280  // FIXME: Replace this with a more optimal version
281  jit_matrix ret;
282 
283  Array<idx_vector> idx;
284  make_indices (indices, idx_count, idx);
285 
286  Matrix temp (1, 1);
287  temp.xelem(0) = value;
288  mat->m_array->assign (idx, temp);
289  ret.update (mat->m_array);
290 
291  return ret;
292  }
293 
294  extern "C" jit_matrix
296  double value)
297  {
298  NDArray *array = mat->m_array;
299  bool done = false;
300 
301  // optimize for the simple case (no resizing and no errors)
302  if (array->jit_ref_count () == 1
303  && index->all_elements_are_ints ())
304  {
305  // this code is similar to idx_vector::fill, but we avoid allocating an
306  // idx_vector and its associated rep
307  octave_idx_type start = static_cast<octave_idx_type> (index->m_base)-1;
308  octave_idx_type step = static_cast<octave_idx_type> (index->m_inc);
309  octave_idx_type nelem = index->m_nelem;
310  octave_idx_type final = start + nelem * step;
311  if (step < 0)
312  {
313  step = -step;
314  std::swap (final, start);
315  }
316 
317  if (start >= 0 && final < mat->m_slice_len)
318  {
319  done = true;
320 
321  double *data = array->jit_slice_data ();
322  if (step == 1)
323  std::fill (data + start, data + start + nelem, value);
324  else
325  {
326  for (octave_idx_type i = start; i < final; i += step)
327  data[i] = value;
328  }
329  }
330  }
331 
332  if (! done)
333  {
334  idx_vector idx (*index);
335  NDArray avalue (dim_vector (1, 1));
336  avalue.xelem (0) = value;
337  array->assign (idx, avalue);
338  }
339 
340  jit_matrix ret;
341  ret.update (array);
342  return ret;
343  }
344 
345  extern "C" double
347  octave_idx_type count)
348  {
349  octave_idx_type ndim = mat->m_dimensions[-1];
350  if (ndim == count)
351  return mat->m_dimensions[idx];
352  else if (ndim > count)
353  {
354  if (idx == count - 1)
355  {
356  double ret = mat->m_dimensions[idx];
357  for (octave_idx_type i = idx + 1; i < ndim; ++i)
358  ret *= mat->m_dimensions[idx];
359  return ret;
360  }
361 
362  return mat->m_dimensions[idx];
363  }
364  else // ndim < count
365  return idx < ndim ? mat->m_dimensions[idx] : 1;
366  }
367 
368  extern "C" octave_base_value *
370  {
371  octave_value undef;
372  octave_base_value *ret = undef.internal_rep ();
373  ret->grab ();
374 
375  return ret;
376  }
377 
378  extern "C" Complex
380  {
381  if (lhs.imag () == 0 && rhs.imag() == 0)
382  return Complex (lhs.real () * rhs.real (), 0);
383 
384  return lhs * rhs;
385  }
386 
387  extern "C" Complex
389  {
390  return lhs / rhs;
391  }
392 
393  // FIXME: CP form src/xpow.cc
394  static inline int
395  xisint (double x)
396  {
397  return (math::x_nint (x) == x
398  && ((x >= 0 && x < std::numeric_limits<int>::max ())
399  || (x <= 0 && x > std::numeric_limits<int>::min ())));
400  }
401 
402  extern "C" Complex
403  octave_jit_pow_scalar_scalar (double lhs, double rhs)
404  {
405  // FIXME: almost CP from src/xpow.cc
406  if (lhs < 0.0 && ! xisint (rhs))
407  return std::pow (Complex (lhs), rhs);
408  return std::pow (lhs, rhs);
409  }
410 
411  extern "C" Complex
413  {
414  if (lhs.imag () == 0 && rhs.imag () == 0)
415  return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ());
416  return std::pow (lhs, rhs);
417  }
418 
419  extern "C" Complex
421  {
422  if (lhs.imag () == 0)
423  return octave_jit_pow_scalar_scalar (lhs.real (), rhs);
424  return std::pow (lhs, rhs);
425  }
426 
427  extern "C" Complex
429  {
430  if (rhs.imag () == 0)
431  return octave_jit_pow_scalar_scalar (lhs, rhs.real ());
432  return std::pow (lhs, rhs);
433  }
434 
435  extern "C" void
437  {
438  octave_stdout << *m << std::endl;
439  }
440 
441  OCTAVE_NORETURN static
442  void
444  {
445  error ("incorrect type information given to the JIT compiler");
446  }
447 
448  // FIXME: Add support for multiple outputs
449  extern "C" octave_base_value *
451  octave_base_value **argin, jit_type *result_type)
452  {
453  octave_value_list ovl (nargin);
454  for (size_t i = 0; i < nargin; ++i)
455  ovl.xelem (i) = octave_value (argin[i]);
456 
457  ovl = fn (ovl, 1);
458 
459  // FIXME: Check result_type somehow
460  if (result_type)
461  {
462  if (ovl.length () < 1)
463  err_bad_result ();
464 
465  octave_value result = ovl.xelem(0);
466  octave_base_value *ret = result.internal_rep ();
467  ret->grab ();
468  return ret;
469  }
470 
471  if (! (ovl.empty ()
472  || (ovl.length () == 1 && ovl.xelem (0).is_undefined ())))
473  err_bad_result ();
474 
475  return 0;
476  }
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.m_base << ", " << rng.m_limit
491  << ", " << rng.m_inc << ", " << rng.m_nelem << ']';
492  }
493 
494 
495  // -------------------- jit_matrix --------------------
496 
497  std::ostream&
498  operator<< (std::ostream& os, const jit_matrix& mat)
499  {
500  return os << "Matrix[" << mat.m_ref_count << ", "
501  << mat.m_slice_data << ", " << mat.m_slice_len << ", "
502  << mat.m_dimensions << ", " << mat.m_array << ']';
503  }
504 
505 
506  // -------------------- jit_type --------------------
507 
508  jit_type::jit_type (const std::string& aname, jit_type *aparent,
509  llvm::Type *allvm_type, bool askip_paren, int aid)
510  : m_name (aname), m_parent (aparent), m_llvm_type (allvm_type), m_id (aid),
511  m_depth (aparent ? aparent->m_depth + 1 : 0), m_skip_paren (askip_paren)
512  {
513  std::memset (m_sret, 0, sizeof (m_sret));
514  std::memset (m_pointer_arg, 0, sizeof (m_pointer_arg));
515  std::memset (m_pack, 0, sizeof (m_pack));
516  std::memset (m_unpack, 0, sizeof (m_unpack));
517 
518  for (size_t i = 0; i < jit_convention::length; ++i)
520  }
521 
522  llvm::Type *
524  {
525  return m_llvm_type ? m_llvm_type->getPointerTo () : nullptr;
526  }
527 
528  jit_type*
530  {
531  // empty case
532  if (! lhs)
533  return rhs;
534 
535  if (! rhs)
536  return lhs;
537 
538  // check for a shared parent
539  while (lhs != rhs)
540  {
541  if (lhs->depth () > rhs->depth ())
542  lhs = lhs->parent ();
543  else if (lhs->depth () < rhs->depth ())
544  rhs = rhs->parent ();
545  else
546  {
547  // we MUST have depth > 0 as any is the base type of everything
548  do
549  {
550  lhs = lhs->parent ();
551  rhs = rhs->parent ();
552  }
553  while (lhs != rhs);
554  }
555  }
556  return lhs;
557  }
558 
559 
560  // -------------------- jit_function --------------------
562  : m_module (nullptr), m_llvm_function (nullptr), m_result (nullptr),
563  m_call_conv (jit_convention::length), m_can_error (false)
564  { }
565 
567  jit_convention::type acall_conv,
568  const llvm::Twine& aname, jit_type *aresult,
569  const std::vector<jit_type *>& aargs)
570  : m_module (amodule), m_result (aresult), m_args (aargs),
571  m_call_conv (acall_conv), m_can_error (false)
572  {
573  llvm::SmallVector<llvm::Type *, 15> llvm_args;
574 
575  llvm::Type *rtype = llvm::Type::getVoidTy (context);
576  if (m_result)
577  {
578  rtype = m_result->packed_type (m_call_conv);
579  if (sret ())
580  {
581  llvm_args.push_back (rtype->getPointerTo ());
582  rtype = llvm::Type::getVoidTy (context);
583  }
584  }
585 
586  for (auto iter = m_args.cbegin (); iter != m_args.cend (); ++iter)
587  {
588  jit_type *ty = *iter;
589  assert (ty);
590  llvm::Type *argty = ty->packed_type (m_call_conv);
591  if (ty->pointer_arg (m_call_conv))
592  argty = argty->getPointerTo ();
593 
594  llvm_args.push_back (argty);
595  }
596 
597  llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false);
599 
600  if (sret ())
601  {
602 #if defined (FUNCTION_ADDATTRIBUTE_ARG_IS_ATTRIBUTES)
603  llvm::AttrBuilder attr_builder;
604  attr_builder.addAttribute (llvm::Attributes::StructRet);
605  llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
606  m_llvm_function->addAttribute (1, attrs);
607 #else
608  m_llvm_function->addAttribute (1, llvm::Attribute::StructRet);
609 #endif
610  }
611 
613 #if defined (FUNCTION_ADDFNATTR_ARG_IS_ATTRIBUTES)
614  m_llvm_function->addFnAttr (llvm::Attributes::AlwaysInline);
615 #else
616  m_llvm_function->addFnAttr (llvm::Attribute::AlwaysInline);
617 #endif
618  }
619 
621  const std::vector<jit_type *>& aargs)
622  : m_module (fn.m_module), m_llvm_function (fn.m_llvm_function),
623  m_result (aresult), m_args (aargs), m_call_conv (fn.m_call_conv),
624  m_can_error (fn.m_can_error)
625  { }
626 
628  : m_module (fn.m_module), m_llvm_function (fn.m_llvm_function),
629  m_result (fn.m_result), m_args (fn.m_args), m_call_conv (fn.m_call_conv),
630  m_can_error (fn.m_can_error)
631  { }
632 
633  void
635  {
636  if (! m_llvm_function)
637  return;
638 
639  m_llvm_function->eraseFromParent ();
640  m_llvm_function = 0;
641  }
642 
643  std::string
644  jit_function::name (void) const
645  {
646  return m_llvm_function->getName ();
647  }
648 
649  llvm::BasicBlock *
650  jit_function::new_block (const std::string& aname,
651  llvm::BasicBlock *insert_before)
652  {
653  return llvm::BasicBlock::Create (context, aname, m_llvm_function,
654  insert_before);
655  }
656 
657  llvm::Value *
659  const std::vector<jit_value *>& in_args) const
660  {
661  if (! valid ())
662  throw jit_fail_exception ("Call not implemented");
663 
664  assert (in_args.size () == m_args.size ());
665  std::vector<llvm::Value *> llvm_args (m_args.size ());
666  for (size_t i = 0; i < in_args.size (); ++i)
667  llvm_args[i] = in_args[i]->to_llvm ();
668 
669  return call (builder, llvm_args);
670  }
671 
672  llvm::Value *
674  const std::vector<llvm::Value *>& in_args) const
675  {
676  if (! valid ())
677  throw jit_fail_exception ("Call not implemented");
678 
679  assert (in_args.size () == m_args.size ());
680  llvm::SmallVector<llvm::Value *, 10> llvm_args;
681  llvm_args.reserve (in_args.size () + sret ());
682 
683  llvm::BasicBlock *insert_block = builder.GetInsertBlock ();
684  llvm::Function *parent = insert_block->getParent ();
685  assert (parent);
686 
687  // Insert allocas inside the prelude block to prevent stack overflows
688  llvm::BasicBlock& prelude = parent->getEntryBlock ();
689  llvm::IRBuilder<> pre_builder (&prelude, prelude.begin ());
690 
691  llvm::AllocaInst *sret_mem = nullptr;
692  if (sret ())
693  {
694  sret_mem = pre_builder.CreateAlloca (m_result->packed_type (m_call_conv));
695  llvm_args.push_back (sret_mem);
696  }
697 
698  for (size_t i = 0; i < in_args.size (); ++i)
699  {
700  llvm::Value *arg = in_args[i];
702  if (convert)
703  arg = convert (builder, arg);
704 
705  if (m_args[i]->pointer_arg (m_call_conv))
706  {
707  llvm::Type *ty = m_args[i]->packed_type (m_call_conv);
708  llvm::Value *alloca = pre_builder.CreateAlloca (ty);
709  builder.CreateStore (arg, alloca);
710  arg = alloca;
711  }
712 
713  llvm_args.push_back (arg);
714  }
715 
716  llvm::CallInst *callinst = builder.CreateCall (m_llvm_function, llvm_args);
717  llvm::Value *ret = callinst;
718 
719  if (sret ())
720  {
721 #if defined (CALLINST_ADDATTRIBUTE_ARG_IS_ATTRIBUTES)
722  llvm::AttrBuilder attr_builder;
723  attr_builder.addAttribute(llvm::Attributes::StructRet);
724  llvm::Attributes attrs = llvm::Attributes::get(context, attr_builder);
725  callinst->addAttribute (1, attrs);
726 #else
727  callinst->addAttribute (1, llvm::Attribute::StructRet);
728 #endif
729  ret = builder.CreateLoad (sret_mem);
730  }
731 
732  if (m_result)
733  {
735  if (unpack)
736  ret = unpack (builder, ret);
737  }
738 
739  return ret;
740  }
741 
742  llvm::Value *
744  {
745  assert (idx < m_args.size ());
746 
747  // FIXME: We should be treating arguments like a list, not a vector.
748  // Shouldn't matter much for now, as the number of arguments shouldn't
749  // be much bigger than 4
750  auto iter = m_llvm_function->arg_begin ();
751  if (sret ())
752  ++iter;
753 
754  for (size_t i = 0; i < idx; ++i, ++iter);
755 
756  if (m_args[idx]->pointer_arg (m_call_conv))
757  return builder.CreateLoad (&*iter);
758 
759  return &*iter;
760  }
761 
762  void
764  bool verify)
765  {
766  assert (! rval == ! m_result);
767 
768  if (rval)
769  {
771  if (convert)
772  rval = convert (builder, rval);
773 
774  if (sret ())
775  {
776  builder.CreateStore (rval, &*(m_llvm_function->arg_begin ()));
777  builder.CreateRetVoid ();
778  }
779  else
780  builder.CreateRet (rval);
781  }
782  else
783  builder.CreateRetVoid ();
784 
785  if (verify)
786  llvm::verifyFunction (*m_llvm_function);
787  }
788 
789  std::ostream&
790  operator<< (std::ostream& os, const jit_function& fn)
791  {
792  llvm::Function *lfn = fn.to_llvm ();
793  os << "jit_function: cc=" << fn.m_call_conv;
794  llvm::raw_os_ostream llvm_out (os);
795  lfn->print (llvm_out);
796  llvm_out.flush ();
797  return os;
798  }
799 
800  // -------------------- jit_operation --------------------
802  {
803  for (auto iter = m_generated.begin (); iter != m_generated.end (); ++iter)
804  {
805  delete iter->first;
806  delete iter->second;
807  }
808  }
809 
810  void
812  const std::vector<jit_type*>& args)
813  {
814  // Number of input arguments of the overload that is being registered
815  size_t nargs = args.size ();
816 
817  if (nargs >= m_overloads.size ())
818  m_overloads.resize (nargs + 1);
819 
820  Array<jit_function>& over = m_overloads[nargs];
821  dim_vector dv (over.dims ());
822  Array<octave_idx_type> idx = to_idx (args);
823  bool must_resize = false;
824 
825  if (dv.length () != idx.numel ())
826  {
827  dv.resize (idx.numel ());
828  must_resize = true;
829  }
830 
831  for (octave_idx_type i = 0; i < dv.length (); ++i)
832  if (dv(i) <= idx(i))
833  {
834  must_resize = true;
835  dv(i) = idx(i) + 1;
836  }
837 
838  if (must_resize)
839  over.resize (dv);
840 
841  over(idx) = func;
842  }
843 
844  const jit_function&
845  jit_operation::overload (const std::vector<jit_type*>& types) const
846  {
847  // Number of input arguments of the overload that is being looked for
848  size_t nargs = types.size ();
849 
850  static jit_function null_overload;
851  for (size_t i = 0; i < nargs; ++i)
852  if (! types[i])
853  return null_overload;
854 
855  if (nargs >= m_overloads.size ())
856  return do_generate (types);
857 
858  const Array<jit_function>& over = m_overloads[nargs];
859  dim_vector dv (over.dims ());
860  Array<octave_idx_type> idx = to_idx (types);
861  for (octave_idx_type i = 0; i < dv.length (); ++i)
862  if (idx(i) >= dv(i))
863  return do_generate (types);
864 
865  const jit_function& ret = over(idx);
866  if (! ret.valid ())
867  return do_generate (types);
868 
869  return ret;
870  }
871 
873  jit_operation::to_idx (const std::vector<jit_type*>& types) const
874  {
875  octave_idx_type numel = types.size ();
876  numel = std::max (numel, static_cast<octave_idx_type> (2));
877 
879  for (octave_idx_type i = 0;
880  i < static_cast<octave_idx_type> (types.size ());
881  ++i)
882  idx(i) = types[i]->type_id ();
883 
884  if (types.size () == 0)
885  idx(0) = idx(1) = 0;
886  if (types.size () == 1)
887  {
888  idx(1) = idx(0);
889  idx(0) = 0;
890  }
891 
892  return idx;
893  }
894 
895  const jit_function&
897  {
898  static jit_function null_overload;
899  generated_map::const_iterator find = m_generated.find (&types);
900  if (find != m_generated.end ())
901  {
902  if (find->second)
903  return *find->second;
904  else
905  return null_overload;
906  }
907 
908  jit_function *ret = generate (types);
909  m_generated[new signature_vec (types)] = ret;
910  return ret ? *ret : null_overload;
911  }
912 
913  jit_function *
915  {
916  return 0;
917  }
918 
919  bool
921  const signature_vec *rhs) const
922  {
923  const signature_vec& l = *lhs;
924  const signature_vec& r = *rhs;
925 
926  if (l.size () < r.size ())
927  return true;
928  else if (l.size () > r.size ())
929  return false;
930 
931  for (size_t i = 0; i < l.size (); ++i)
932  {
933  if (l[i]->type_id () < r[i]->type_id ())
934  return true;
935  else if (l[i]->type_id () > r[i]->type_id ())
936  return false;
937  }
938 
939  return false;
940  }
941 
942  // -------------------- jit_index_operation --------------------
943  jit_function *
945  {
946  if (types.size () > 2 && types[0] == jit_typeinfo::get_matrix ())
947  {
948  // indexing a matrix with scalars
950  for (size_t i = 1; i < types.size (); ++i)
951  if (types[i] != scalar)
952  return 0;
953 
954  return generate_matrix (types);
955  }
956 
957  return 0;
958  }
959 
960  llvm::Value *
962  const jit_function& fn,
963  size_t start_idx,
964  size_t end_idx) const
965  {
966  size_t n = end_idx - start_idx;
967  llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
968  llvm::ArrayType *array_t = llvm::ArrayType::get (scalar_t, n);
969  llvm::Value *array = llvm::UndefValue::get (array_t);
970  for (size_t i = start_idx; i < end_idx; ++i)
971  {
972  llvm::Value *idx = fn.argument (builder, i);
973  array = builder.CreateInsertValue (array, idx, i - start_idx);
974  }
975 
976  llvm::Value *array_mem = builder.CreateAlloca (array_t);
977  builder.CreateStore (array, array_mem);
978  return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ());
979  }
980 
981  // -------------------- jit_paren_subsref --------------------
982 
984  : jit_index_operation (ti, "()subsref"), m_paren_scalar (nullptr)
985  { }
986 
988  {
989  delete m_paren_scalar;
990  }
991 
992  jit_function *
994  {
995  if (m_paren_scalar == nullptr)
996  panic_impossible ();
997 
998  std::stringstream ss;
999  ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1);
1000 
1001  // FIXME: Where will this be deleted?
1002  jit_function *fn = new jit_function
1003  (m_typeinfo.create_internal (ss.str (), m_typeinfo.m_scalar, types));
1004 
1005  fn->mark_can_error ();
1006  llvm::BasicBlock *body = fn->new_block ();
1007  llvm::IRBuilder<> builder (body);
1008 
1009  llvm::Value *array = create_arg_array (builder, *fn, 1, types.size ());
1010  llvm::Value *nelem = llvm::ConstantInt::get (m_typeinfo.m_index_t,
1011  types.size () - 1);
1012  llvm::Value *mat = fn->argument (builder, 0);
1013  llvm::Value *ret = m_paren_scalar->call (builder, mat, array, nelem);
1014  fn->do_return (builder, ret);
1015  return fn;
1016  }
1017 
1018  void
1020  {
1021  std::vector<jit_type *> types (3);
1022  types[0] = m_typeinfo.m_matrix;
1023  types[1] = m_typeinfo.m_scalar_ptr;
1024  types[2] = m_typeinfo.m_index;
1025 
1028  "octave_jit_paren_scalar",
1029  m_typeinfo.m_scalar, types));
1030 
1032  }
1033 
1034  // -------------------- jit_paren_subsasgn --------------------
1035 
1037  : jit_index_operation (ti, "()subsasgn"), m_paren_scalar (nullptr)
1038  { }
1039 
1041  {
1042  delete m_paren_scalar;
1043  }
1044 
1045  jit_function *
1047  {
1048  if (m_paren_scalar == nullptr)
1049  panic_impossible ();
1050 
1051  std::stringstream ss;
1052  ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2);
1053 
1054  // FIXME: Where will this be deleted?
1055  jit_function *fn = new jit_function
1056  (m_typeinfo.create_internal (ss.str (), m_typeinfo.m_matrix, types));
1057 
1058  fn->mark_can_error ();
1059  llvm::BasicBlock *body = fn->new_block ();
1060  llvm::IRBuilder<> builder (body);
1061 
1062  llvm::Value *array = create_arg_array (builder, *fn, 1, types.size () - 1);
1063  llvm::Value *nelem = llvm::ConstantInt::get (m_typeinfo.m_index_t,
1064  types.size () - 2);
1065 
1066  llvm::Value *mat = fn->argument (builder, 0);
1067  llvm::Value *value = fn->argument (builder, types.size () - 1);
1068  llvm::Value *ret = m_paren_scalar->call (builder, mat, array, nelem, value);
1069  fn->do_return (builder, ret);
1070 
1071  return fn;
1072  }
1073 
1074  void
1076  {
1077  std::vector<jit_type *> types (4);
1078  types[0] = m_typeinfo.m_matrix;
1079  types[1] = m_typeinfo.m_scalar_ptr;
1080  types[2] = m_typeinfo.m_index;
1081  types[3] = m_typeinfo.m_scalar;
1082 
1085  "octave_jit_paren_scalar",
1086  m_typeinfo.m_matrix, types));
1087 
1089  }
1090 
1091 
1092  // -------------------- jit_typeinfo --------------------
1093 
1094  bool jit_typeinfo::s_in_construction = false;
1095 
1096  // Static method that holds the singleton instance
1097  jit_typeinfo&
1099  {
1100  if (s_in_construction)
1101  // This state is typically reached when the constructor calls one
1102  // of the static methods of the singleton class...
1103  panic_impossible ();
1104 
1105  static jit_typeinfo typeinfo;
1106  return typeinfo;
1107  }
1108 
1110  {
1111  while (! m_id_to_type.empty ())
1112  {
1113  delete m_id_to_type.back ();
1114  m_id_to_type.pop_back ();
1115  }
1116 
1117  delete m_builder_ptr;
1118  delete m_base_jit_module;
1119  }
1120 
1121  // wrap function names to simplify jit_typeinfo::create_external
1122 #define JIT_FN(fn) &fn, #fn
1123 
1125  : paren_subsref_fn (*this),
1126  paren_subsasgn_fn (*this),
1127  m_next_id (0),
1128  m_grab_fn ("grab"),
1129  m_release_fn ("release"),
1130  m_destroy_fn ("destroy"),
1131  m_print_fn ("print"),
1132  m_for_init_fn ("for_init"),
1133  m_for_check_fn ("for_check"),
1134  m_for_index_fn ("for_index"),
1135  m_logically_true_fn ("logically_true"),
1136  m_make_range_fn ("make_range"),
1137  m_end1_fn ("end1"),
1138  m_end_fn ("end"),
1139  m_create_undef_fn ("create_undef"),
1140  m_base_jit_module (new jit_module ("octaveJITBaseModule")),
1141  m_builder_ptr (new llvm::IRBuilderD (context)),
1142  // FIXME: Use a pointer directly in the constructor, and get rid of this
1143  m_builder (*m_builder_ptr)
1144  {
1145  s_in_construction = true;
1146 
1147  // ----- Register basic JIT types -----
1148 
1149  // FIXME: It seems that our type lattice is not really a lattice
1150  // since any and any_ptr have no common upper_bound (?!?)
1151 
1152  // jit_types: "any" < (nullptr)
1153  // "any_ptr" < (nullptr)
1154  m_any_t = llvm::StructType::create (context, "octave_base_value");
1155  m_any_t = m_any_t->getPointerTo ();
1156  m_any = do_register_new_type ("any", nullptr, m_any_t);
1157  m_any_ptr = do_register_new_type ("any_ptr", nullptr,
1158  m_any_t->getPointerTo ());
1159 
1160  // jit_types: "scalar" < "complex" < "any"
1161  // and: "scalar_ptr" < (nullptr)
1162  // FIXME: what about sing-precision floats ???
1163  // FIXME: shouldn't we make scalar_ptr a sub_type of any_ptr ?
1164  m_scalar_t = llvm::Type::getDoubleTy (context);
1165  m_complex_t = llvm::ArrayType::get (m_scalar_t, 2);
1168  m_scalar_ptr = do_register_new_type ("scalar_ptr", nullptr,
1169  m_scalar_t->getPointerTo ());
1170 
1171  // jit_type: "bool" < "any"
1172  m_bool_t = llvm::Type::getInt1Ty (context);
1174 
1175  // jit_types: "int8", "int16", "int32", "int64" < "any"
1176  m_ints[ 8] = do_register_new_type ("int8", m_any,
1177  llvm::Type::getIntNTy (context, 8));
1178  m_ints[16] = do_register_new_type ("int16", m_any,
1179  llvm::Type::getIntNTy (context, 16));
1180  m_ints[32] = do_register_new_type ("int32", m_any,
1181  llvm::Type::getIntNTy (context, 32));
1182  m_ints[64] = do_register_new_type ("int64", m_any,
1183  llvm::Type::getIntNTy (context, 64));
1184 
1185  // jit_type: "string" < "any"
1186  m_string_t = llvm::Type::getInt8Ty (context);
1187  m_string_t = m_string_t->getPointerTo ();
1189 
1190  // jit_type: "index" < "any"
1191  m_index_t = llvm::Type::getIntNTy (context, sizeof (octave_idx_type) * 8);
1193 
1194  // jit_type: "range" < "any"
1195  m_range_t = llvm::StructType::create (context, "range");
1196  {
1197  std::vector<llvm::Type *> range_contents (4, m_scalar_t);
1198  range_contents[3] = m_index_t;
1199  m_range_t->setBody (range_contents);
1200  }
1202 
1203  // jit_type: "matrix" < "any"
1204  m_matrix_t = llvm::StructType::create (context, "matrix");
1205  {
1206  llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8);
1207  llvm::Type *matrix_contents[5];
1208  matrix_contents[0] = refcount_t->getPointerTo ();
1209  matrix_contents[1] = m_scalar_t->getPointerTo ();
1210  matrix_contents[2] = m_index_t;
1211  matrix_contents[3] = m_index_t->getPointerTo ();
1212  matrix_contents[4] = m_string_t;
1213  m_matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5));
1214  }
1216 
1217  // ----- Specify calling conventions -----
1218 
1219  // complex_ret is what is passed to C functions
1220  // in order to get calling convention right
1221  m_complex_ret = llvm::StructType::create (context, "complex_ret");
1222  {
1223  llvm::Type *cmplx_inner_cont[] = {m_scalar_t, m_scalar_t};
1224  llvm::StructType *cmplx_inner = llvm::StructType::create (cmplx_inner_cont);
1225  llvm::Type *contents[] = {cmplx_inner};
1226  m_complex_ret->setBody (contents);
1227  }
1228 
1229  // FIXME: We should detect architecture and do something sane
1230  // based on that here we assume x86 or x86_64
1233 
1236 
1242 
1243  if (sizeof (void *) == 4)
1245 
1248 
1249  // bind global variables
1251  "error_state");
1252 
1254 
1255  // sig_atomic_type is going to be some sort of integer
1256  m_sig_atomic_type = llvm::Type::getIntNTy (context,
1257  sizeof(sig_atomic_t) * 8);
1258 
1260  (m_sig_atomic_type, false, "octave_interrupt_state");
1261 
1264 
1265  // generic call function
1266  {
1267  jit_type *int_t = do_get_intN (sizeof (octave_builtin::fcn) * 8);
1269  int_t, m_any_ptr, int_t);
1270  }
1271 
1272  // any with anything is an any op
1273  jit_function fn;
1274  jit_type *binary_op_type = do_get_intN (sizeof (octave_value::binary_op) * 8);
1275  llvm::Type *llvm_bo_type = binary_op_type->to_llvm ();
1277  m_any, binary_op_type,
1278  m_any, m_any);
1279  any_binary.mark_can_error ();
1280 
1281  for (size_t i = 0; i < octave_value::num_binary_ops; ++i)
1282  {
1283  octave_value::binary_op op = static_cast<octave_value::binary_op> (i);
1284  std::string op_name = octave_value::binary_op_as_string (op);
1285  m_binary_ops.push_back (jit_operation ("binary" + op_name));
1286  }
1287 
1288  for (size_t i = 0; i < octave_value::num_unary_ops; ++i)
1289  {
1290  octave_value::unary_op op = static_cast<octave_value::unary_op> (i);
1291  std::string op_name = octave_value::unary_op_as_string (op);
1292  m_unary_ops.push_back (jit_operation ("unary" + op_name));
1293  }
1294 
1295  for (int op = 0; op < octave_value::num_binary_ops; ++op)
1296  {
1297  const llvm::Twine& fn_name
1298  = "octave_jit_binary_any_any_" + llvm::Twine (op);
1299 
1300  fn = create_internal (fn_name, m_any, m_any, m_any);
1301  fn.mark_can_error ();
1302  llvm::BasicBlock *block = fn.new_block ();
1303  m_builder.SetInsertPoint (block);
1304  llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op,
1305  std::numeric_limits<octave_value::binary_op>::is_signed);
1306  llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int);
1307  llvm::Value *ret = any_binary.call (m_builder, op_as_llvm,
1308  fn.argument (m_builder, 0),
1309  fn.argument (m_builder, 1));
1310  fn.do_return (m_builder, ret);
1311  m_binary_ops[op].add_overload (fn);
1312  }
1313 
1314  // grab matrix
1316  m_grab_fn.add_overload (fn);
1323 
1324  // release any
1327 
1328  // release matrix
1330  m_matrix);
1332 
1333  // destroy
1339 
1340  // -------------------- scalar related operations --------------------
1341 
1342  // now for binary scalar operations
1343  add_binary_op (m_scalar, octave_value::op_add, llvm::Instruction::FAdd);
1344  add_binary_op (m_scalar, octave_value::op_sub, llvm::Instruction::FSub);
1345  add_binary_op (m_scalar, octave_value::op_mul, llvm::Instruction::FMul);
1346  add_binary_op (m_scalar, octave_value::op_el_mul, llvm::Instruction::FMul);
1347 
1348  add_binary_fcmp (m_scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT);
1349  add_binary_fcmp (m_scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE);
1350  add_binary_fcmp (m_scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ);
1351  add_binary_fcmp (m_scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE);
1352  add_binary_fcmp (m_scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT);
1353  add_binary_fcmp (m_scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE);
1354 
1355  // divide is annoying because it might error
1356  fn = create_internal ("octave_jit_div_scalar_scalar", m_scalar, m_scalar,
1357  m_scalar);
1358  fn.mark_can_error ();
1359 
1360  llvm::BasicBlock *body = fn.new_block ();
1361  m_builder.SetInsertPoint (body);
1362  {
1363  llvm::BasicBlock *warn_block = fn.new_block ("warn");
1364  llvm::BasicBlock *normal_block = fn.new_block ("normal");
1365 
1366  llvm::Value *zero = llvm::ConstantFP::get (m_scalar_t, 0);
1367  llvm::Value *check = m_builder.CreateFCmpUEQ (zero,
1368  fn.argument (m_builder, 1));
1369  m_builder.CreateCondBr (check, warn_block, normal_block);
1370 
1371  m_builder.SetInsertPoint (warn_block);
1372  m_builder.CreateBr (normal_block);
1373 
1374  m_builder.SetInsertPoint (normal_block);
1375  llvm::Value *ret = m_builder.CreateFDiv (fn.argument (m_builder, 0),
1376  fn.argument (m_builder, 1));
1377  fn.do_return (m_builder, ret);
1378  }
1379  m_binary_ops[octave_value::op_div].add_overload (fn);
1380  m_binary_ops[octave_value::op_el_div].add_overload (fn);
1381 
1382  // ldiv is the same as div with the operators reversed
1383  fn = mirror_binary (fn);
1384  m_binary_ops[octave_value::op_ldiv].add_overload (fn);
1385  m_binary_ops[octave_value::op_el_ldiv].add_overload (fn);
1386 
1387  // In general, the result of scalar ^ scalar is a complex number. We might
1388  // be able to improve on this if we keep track of the range of values
1389  // variables can take on.
1391  m_scalar, m_scalar);
1392  m_binary_ops[octave_value::op_pow].add_overload (fn);
1393  m_binary_ops[octave_value::op_el_pow].add_overload (fn);
1394 
1395  // now for unary scalar operations
1396  // FIXME: Implement not
1397  fn = create_internal ("octave_jit_++", m_scalar, m_scalar);
1398  body = fn.new_block ();
1399  m_builder.SetInsertPoint (body);
1400  {
1401  llvm::Value *one = llvm::ConstantFP::get (m_scalar_t, 1);
1402  llvm::Value *val = fn.argument (m_builder, 0);
1403  val = m_builder.CreateFAdd (val, one);
1404  fn.do_return (m_builder, val);
1405  }
1406  m_unary_ops[octave_value::op_incr].add_overload (fn);
1407 
1408  fn = create_internal ("octave_jit_--", m_scalar, m_scalar);
1409  body = fn.new_block ();
1410  m_builder.SetInsertPoint (body);
1411  {
1412  llvm::Value *one = llvm::ConstantFP::get (m_scalar_t, 1);
1413  llvm::Value *val = fn.argument (m_builder, 0);
1414  val = m_builder.CreateFSub (val, one);
1415  fn.do_return (m_builder, val);
1416  }
1417  m_unary_ops[octave_value::op_decr].add_overload (fn);
1418 
1419  fn = create_internal ("octave_jit_uminus", m_scalar, m_scalar);
1420  body = fn.new_block ();
1421  m_builder.SetInsertPoint (body);
1422  {
1423  llvm::Value *mone = llvm::ConstantFP::get (m_scalar_t, -1);
1424  llvm::Value *val = fn.argument (m_builder, 0);
1425  val = m_builder.CreateFMul (val, mone);
1426  fn.do_return (m_builder, val);
1427  }
1428  m_unary_ops[octave_value::op_uminus].add_overload (fn);
1429 
1430  fn = create_identity (m_scalar);
1431  m_unary_ops[octave_value::op_uplus].add_overload (fn);
1432  m_unary_ops[octave_value::op_transpose].add_overload (fn);
1433  m_unary_ops[octave_value::op_hermitian].add_overload (fn);
1434 
1435  // now for binary complex operations
1436  fn = create_internal ("octave_jit_+_complex_complex", m_complex, m_complex,
1437  m_complex);
1438  body = fn.new_block ();
1439  m_builder.SetInsertPoint (body);
1440  {
1441  llvm::Value *lhs = fn.argument (m_builder, 0);
1442  llvm::Value *rhs = fn.argument (m_builder, 1);
1443  llvm::Value *real = m_builder.CreateFAdd (complex_real (lhs),
1444  complex_real (rhs));
1445  llvm::Value *imag = m_builder.CreateFAdd (complex_imag (lhs),
1446  complex_imag (rhs));
1448  }
1449  m_binary_ops[octave_value::op_add].add_overload (fn);
1450 
1451  fn = create_internal ("octave_jit_-_complex_complex", m_complex, m_complex,
1452  m_complex);
1453  body = fn.new_block ();
1454  m_builder.SetInsertPoint (body);
1455  {
1456  llvm::Value *lhs = fn.argument (m_builder, 0);
1457  llvm::Value *rhs = fn.argument (m_builder, 1);
1458  llvm::Value *real = m_builder.CreateFSub (complex_real (lhs),
1459  complex_real (rhs));
1460  llvm::Value *imag = m_builder.CreateFSub (complex_imag (lhs),
1461  complex_imag (rhs));
1463  }
1464  m_binary_ops[octave_value::op_sub].add_overload (fn);
1465 
1468  m_binary_ops[octave_value::op_mul].add_overload (fn);
1469  m_binary_ops[octave_value::op_el_mul].add_overload (fn);
1470 
1473  complex_div.mark_can_error ();
1474  m_binary_ops[octave_value::op_div].add_overload (fn);
1475  m_binary_ops[octave_value::op_ldiv].add_overload (fn);
1476 
1478  m_complex, m_complex);
1479  m_binary_ops[octave_value::op_pow].add_overload (fn);
1480  m_binary_ops[octave_value::op_el_pow].add_overload (fn);
1481 
1482  fn = create_internal ("octave_jit_*_scalar_complex", m_complex, m_scalar,
1483  m_complex);
1484  jit_function mul_scalar_complex = fn;
1485  body = fn.new_block ();
1486  m_builder.SetInsertPoint (body);
1487  {
1488  llvm::BasicBlock *complex_mul = fn.new_block ("complex_mul");
1489  llvm::BasicBlock *scalar_mul = fn.new_block ("scalar_mul");
1490 
1491  llvm::Value *fzero = llvm::ConstantFP::get (m_scalar_t, 0);
1492  llvm::Value *lhs = fn.argument (m_builder, 0);
1493  llvm::Value *rhs = fn.argument (m_builder, 1);
1494 
1495  llvm::Value *cmp = m_builder.CreateFCmpUEQ (complex_imag (rhs), fzero);
1496  m_builder.CreateCondBr (cmp, scalar_mul, complex_mul);
1497 
1498  m_builder.SetInsertPoint (scalar_mul);
1499  llvm::Value *temp = complex_real (rhs);
1500  temp = m_builder.CreateFMul (lhs, temp);
1501  fn.do_return (m_builder, complex_new (temp, fzero), false);
1502 
1503  m_builder.SetInsertPoint (complex_mul);
1504  temp = complex_new (m_builder.CreateFMul (lhs, complex_real (rhs)),
1505  m_builder.CreateFMul (lhs, complex_imag (rhs)));
1506  fn.do_return (m_builder, temp);
1507  }
1508  m_binary_ops[octave_value::op_mul].add_overload (fn);
1509  m_binary_ops[octave_value::op_el_mul].add_overload (fn);
1510 
1511  fn = mirror_binary (mul_scalar_complex);
1512  m_binary_ops[octave_value::op_mul].add_overload (fn);
1513  m_binary_ops[octave_value::op_el_mul].add_overload (fn);
1514 
1515  fn = create_internal ("octave_jit_+_scalar_complex", m_complex, m_scalar,
1516  m_complex);
1517  body = fn.new_block ();
1518  m_builder.SetInsertPoint (body);
1519  {
1520  llvm::Value *lhs = fn.argument (m_builder, 0);
1521  llvm::Value *rhs = fn.argument (m_builder, 1);
1522  llvm::Value *real = m_builder.CreateFAdd (lhs, complex_real (rhs));
1523  fn.do_return (m_builder, complex_real (rhs, real));
1524  }
1525  m_binary_ops[octave_value::op_add].add_overload (fn);
1526 
1527  fn = mirror_binary (fn);
1528  m_binary_ops[octave_value::op_add].add_overload (fn);
1529 
1530  fn = create_internal ("octave_jit_-_complex_scalar", m_complex, m_complex,
1531  m_scalar);
1532  body = fn.new_block ();
1533  m_builder.SetInsertPoint (body);
1534  {
1535  llvm::Value *lhs = fn.argument (m_builder, 0);
1536  llvm::Value *rhs = fn.argument (m_builder, 1);
1537  llvm::Value *real = m_builder.CreateFSub (complex_real (lhs), rhs);
1538  fn.do_return (m_builder, complex_real (lhs, real));
1539  }
1540  m_binary_ops[octave_value::op_sub].add_overload (fn);
1541 
1542  fn = create_internal ("octave_jit_-_scalar_complex", m_complex, m_scalar,
1543  m_complex);
1544  body = fn.new_block ();
1545  m_builder.SetInsertPoint (body);
1546  {
1547  llvm::Value *lhs = fn.argument (m_builder, 0);
1548  llvm::Value *rhs = fn.argument (m_builder, 1);
1549  llvm::Value *real = m_builder.CreateFSub (lhs, complex_real (rhs));
1550  fn.do_return (m_builder, complex_real (rhs, real));
1551  }
1552  m_binary_ops[octave_value::op_sub].add_overload (fn);
1553 
1555  m_scalar, m_complex);
1556  m_binary_ops[octave_value::op_pow].add_overload (fn);
1557  m_binary_ops[octave_value::op_el_pow].add_overload (fn);
1558 
1560  m_complex, m_scalar);
1561  m_binary_ops[octave_value::op_pow].add_overload (fn);
1562  m_binary_ops[octave_value::op_el_pow].add_overload (fn);
1563 
1564  // now for binary index operators
1565  add_binary_op (m_index, octave_value::op_add, llvm::Instruction::Add);
1566 
1567  // and binary bool operators
1568  add_binary_op (m_boolean, octave_value::op_el_or, llvm::Instruction::Or);
1569  add_binary_op (m_boolean, octave_value::op_el_and, llvm::Instruction::And);
1570 
1571  // now for printing functions
1572  add_print (m_any, reinterpret_cast<void *> (&octave_jit_print_any));
1573  add_print (m_scalar, reinterpret_cast<void *> (&octave_jit_print_scalar));
1574 
1575  // initialize for loop
1576  fn = create_internal ("octave_jit_for_range_init", m_index, m_range);
1577  body = fn.new_block ();
1578  m_builder.SetInsertPoint (body);
1579  {
1580  llvm::Value *zero = llvm::ConstantInt::get (m_index_t, 0);
1581  fn.do_return (m_builder, zero);
1582  }
1584 
1585  // bounds check for for loop
1586  fn = create_internal ("octave_jit_for_range_check", m_boolean, m_range,
1587  m_index);
1588  body = fn.new_block ();
1589  m_builder.SetInsertPoint (body);
1590  {
1591  llvm::Value *nelem
1592  = m_builder.CreateExtractValue (fn.argument (m_builder, 0), 3);
1593  llvm::Value *idx = fn.argument (m_builder, 1);
1594  llvm::Value *ret = m_builder.CreateICmpULT (idx, nelem);
1595  fn.do_return (m_builder, ret);
1596  }
1598 
1599  // index variable for for loop
1600  fn = create_internal ("octave_jit_for_range_idx", m_scalar, m_range,
1601  m_index);
1602  body = fn.new_block ();
1603  m_builder.SetInsertPoint (body);
1604  {
1605  llvm::Value *idx = fn.argument (m_builder, 1);
1606  llvm::Value *didx = m_builder.CreateSIToFP (idx, m_scalar_t);
1607  llvm::Value *rng = fn.argument (m_builder, 0);
1608  llvm::Value *base = m_builder.CreateExtractValue (rng, 0);
1609  llvm::Value *inc = m_builder.CreateExtractValue (rng, 2);
1610 
1611  llvm::Value *ret = m_builder.CreateFMul (didx, inc);
1612  ret = m_builder.CreateFAdd (base, ret);
1613  fn.do_return (m_builder, ret);
1614  }
1616 
1617  // logically true
1618  jit_function gripe_nantl
1620  nullptr);
1621  gripe_nantl.mark_can_error ();
1622  fn = create_internal ("octave_jit_logically_true_scalar", m_boolean,
1623  m_scalar);
1624  fn.mark_can_error ();
1625  body = fn.new_block ();
1626  m_builder.SetInsertPoint (body);
1627  {
1628  llvm::BasicBlock *error_block = fn.new_block ("error");
1629  llvm::BasicBlock *normal_block = fn.new_block ("normal");
1630 
1631  llvm::Value *check = m_builder.CreateFCmpUNE (fn.argument (m_builder, 0),
1632  fn.argument (m_builder, 0));
1633  m_builder.CreateCondBr (check, error_block, normal_block);
1634 
1635  m_builder.SetInsertPoint (error_block);
1636  gripe_nantl.call (m_builder);
1637  m_builder.CreateBr (normal_block);
1638  m_builder.SetInsertPoint (normal_block);
1639 
1640  llvm::Value *zero = llvm::ConstantFP::get (m_scalar_t, 0);
1641  llvm::Value *ret = m_builder.CreateFCmpONE (fn.argument (m_builder, 0), zero);
1642  fn.do_return (m_builder, ret);
1643  }
1645 
1646  // logically_true boolean
1647  fn = create_identity (m_boolean);
1649 
1650  // make_range
1651  // FIXME: May be beneficial to implement all in LLVM
1652  jit_function compute_nelem
1655  fn = create_internal ("octave_jit_make_range", m_range, m_scalar, m_scalar,
1656  m_scalar);
1657  body = fn.new_block ();
1658  m_builder.SetInsertPoint (body);
1659  {
1660  llvm::Value *base = fn.argument (m_builder, 0);
1661  llvm::Value *limit = fn.argument (m_builder, 1);
1662  llvm::Value *inc = fn.argument (m_builder, 2);
1663  llvm::Value *nelem = compute_nelem.call (m_builder, base, limit, inc);
1664 
1665  llvm::Value *dzero = llvm::ConstantFP::get (m_scalar_t, 0);
1666  llvm::Value *izero = llvm::ConstantInt::get (m_index_t, 0);
1667  llvm::Value *rng = llvm::ConstantStruct::get (m_range_t, dzero, dzero,
1668  dzero, izero, nullptr);
1669  rng = m_builder.CreateInsertValue (rng, base, 0);
1670  rng = m_builder.CreateInsertValue (rng, limit, 1);
1671  rng = m_builder.CreateInsertValue (rng, inc, 2);
1672  rng = m_builder.CreateInsertValue (rng, nelem, 3);
1673  fn.do_return (m_builder, rng);
1674  }
1676 
1677  // paren_subsref
1678  jit_type *jit_int = do_get_intN (sizeof (int) * 8);
1679  llvm::Type *int_t = jit_int->to_llvm ();
1680  jit_function ginvalid_index
1683  nullptr, jit_int, jit_int,
1684  m_index, m_index);
1685 
1686  fn = create_internal ("()subsref", m_scalar, m_matrix, m_scalar);
1687  fn.mark_can_error ();
1688 
1689  body = fn.new_block ();
1690  m_builder.SetInsertPoint (body);
1691  {
1692  llvm::Value *one_idx = llvm::ConstantInt::get (m_index_t, 1);
1693  llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
1694 
1695  llvm::Value *undef = llvm::UndefValue::get (m_scalar_t);
1696  llvm::Value *mat = fn.argument (m_builder, 0);
1697  llvm::Value *idx = fn.argument (m_builder, 1);
1698 
1699  // convert index to scalar to integer, and check index >= 1
1700  llvm::Value *int_idx = m_builder.CreateFPToSI (idx, m_index_t);
1701  llvm::Value *check_idx = m_builder.CreateSIToFP (int_idx, m_scalar_t);
1702  llvm::Value *cond0 = m_builder.CreateFCmpUNE (idx, check_idx);
1703  llvm::Value *cond1 = m_builder.CreateICmpSLT (int_idx, one_idx);
1704  llvm::Value *cond = m_builder.CreateOr (cond0, cond1);
1705 
1706  llvm::BasicBlock *done = fn.new_block ("done");
1707  llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
1708  llvm::BasicBlock *normal = fn.new_block ("normal", done);
1709  m_builder.CreateCondBr (cond, conv_error, normal);
1710 
1711  m_builder.SetInsertPoint (conv_error);
1712  ginvalid_index.call (m_builder);
1713  m_builder.CreateBr (done);
1714 
1715  m_builder.SetInsertPoint (normal);
1716  llvm::Value *len
1717  = m_builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (2));
1718  cond = m_builder.CreateICmpSGT (int_idx, len);
1719 
1720  llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
1721  llvm::BasicBlock *success = fn.new_block ("success", done);
1722  m_builder.CreateCondBr (cond, bounds_error, success);
1723 
1724  m_builder.SetInsertPoint (bounds_error);
1725  gindex_range.call (m_builder, one_int, one_int, int_idx, len);
1726  m_builder.CreateBr (done);
1727 
1728  m_builder.SetInsertPoint (success);
1729  llvm::Value *data = m_builder.CreateExtractValue (mat,
1730  llvm::ArrayRef<unsigned> (1));
1731  llvm::Value *gep = m_builder.CreateInBoundsGEP (data, int_idx);
1732  llvm::Value *ret = m_builder.CreateLoad (gep);
1733  m_builder.CreateBr (done);
1734 
1735  m_builder.SetInsertPoint (done);
1736 
1737  llvm::PHINode *merge = llvm::PHINode::Create (m_scalar_t, 3);
1738  m_builder.Insert (merge);
1739  merge->addIncoming (undef, conv_error);
1740  merge->addIncoming (undef, bounds_error);
1741  merge->addIncoming (ret, success);
1742  fn.do_return (m_builder, merge);
1743  }
1745 
1746  // paren subsasgn
1747  jit_function resize_paren_subsasgn
1750  fn = create_internal ("octave_jit_paren_subsasgn", m_matrix, m_matrix,
1751  m_scalar, m_scalar);
1752  fn.mark_can_error ();
1753  body = fn.new_block ();
1754  m_builder.SetInsertPoint (body);
1755  {
1756  llvm::Value *one_idx = llvm::ConstantInt::get (m_index_t, 1);
1757  llvm::Value *one_int = llvm::ConstantInt::get (int_t, 1);
1758 
1759  llvm::Value *mat = fn.argument (m_builder, 0);
1760  llvm::Value *idx = fn.argument (m_builder, 1);
1761  llvm::Value *value = fn.argument (m_builder, 2);
1762 
1763  llvm::Value *int_idx = m_builder.CreateFPToSI (idx, m_index_t);
1764  llvm::Value *check_idx = m_builder.CreateSIToFP (int_idx, m_scalar_t);
1765  llvm::Value *cond0 = m_builder.CreateFCmpUNE (idx, check_idx);
1766  llvm::Value *cond1 = m_builder.CreateICmpSLT (int_idx, one_idx);
1767  llvm::Value *cond = m_builder.CreateOr (cond0, cond1);
1768 
1769  llvm::BasicBlock *done = fn.new_block ("done");
1770 
1771  llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done);
1772  llvm::BasicBlock *normal = fn.new_block ("normal", done);
1773  m_builder.CreateCondBr (cond, conv_error, normal);
1774  m_builder.SetInsertPoint (conv_error);
1775  ginvalid_index.call (m_builder);
1776  m_builder.CreateBr (done);
1777 
1778  m_builder.SetInsertPoint (normal);
1779  llvm::Value *len = m_builder.CreateExtractValue (mat, 2);
1780  cond0 = m_builder.CreateICmpSGT (int_idx, len);
1781 
1782  llvm::Value *rcount = m_builder.CreateExtractValue (mat, 0);
1783  rcount = m_builder.CreateLoad (rcount);
1784  cond1 = m_builder.CreateICmpSGT (rcount, one_int);
1785  cond = m_builder.CreateOr (cond0, cond1);
1786 
1787  llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done);
1788  llvm::BasicBlock *success = fn.new_block ("success", done);
1789  m_builder.CreateCondBr (cond, bounds_error, success);
1790 
1791  // resize on out of bounds access
1792  m_builder.SetInsertPoint (bounds_error);
1793  llvm::Value *resize_result = resize_paren_subsasgn.call (m_builder, mat,
1794  int_idx, value);
1795  m_builder.CreateBr (done);
1796 
1797  m_builder.SetInsertPoint (success);
1798  llvm::Value *data
1799  = m_builder.CreateExtractValue (mat, llvm::ArrayRef<unsigned> (1));
1800  llvm::Value *gep = m_builder.CreateInBoundsGEP (data, int_idx);
1801  m_builder.CreateStore (value, gep);
1802  m_builder.CreateBr (done);
1803 
1804  m_builder.SetInsertPoint (done);
1805 
1806  llvm::PHINode *merge = llvm::PHINode::Create (m_matrix_t, 3);
1807  m_builder.Insert (merge);
1808  merge->addIncoming (mat, conv_error);
1809  merge->addIncoming (resize_result, bounds_error);
1810  merge->addIncoming (mat, success);
1811  fn.do_return (m_builder, merge);
1812  }
1814 
1817  fn.mark_can_error ();
1819 
1820  fn = create_internal ("octave_jit_end1_matrix", m_scalar, m_matrix,
1821  m_index, m_index);
1822  body = fn.new_block ();
1823  m_builder.SetInsertPoint (body);
1824  {
1825  llvm::Value *mat = fn.argument (m_builder, 0);
1826  llvm::Value *ret = m_builder.CreateExtractValue (mat, 2);
1827  fn.do_return (m_builder, m_builder.CreateSIToFP (ret, m_scalar_t));
1828  }
1829  m_end1_fn.add_overload (fn);
1830 
1832  m_index, m_index);
1833  m_end_fn.add_overload (fn);
1834 
1835  // -------------------- create_undef --------------------
1838 
1839  m_casts[m_any->type_id ()].stash_name ("(any)");
1840  m_casts[m_scalar->type_id ()].stash_name ("(scalar)");
1841  m_casts[m_complex->type_id ()].stash_name ("(complex)");
1842  m_casts[m_matrix->type_id ()].stash_name ("(matrix)");
1843  m_casts[m_range->type_id ()].stash_name ("(range)");
1844 
1845  // cast m_any <- matrix
1847  m_matrix);
1848  m_casts[m_any->type_id ()].add_overload (fn);
1849 
1850  // cast matrix <- any
1852  m_any);
1853  m_casts[m_matrix->type_id ()].add_overload (fn);
1854 
1855  // cast any <- range
1857  m_casts[m_any->type_id ()].add_overload (fn);
1858 
1859  // cast range <- any
1861  m_casts[m_range->type_id ()].add_overload (fn);
1862 
1863  // cast any <- scalar
1865  m_scalar);
1866  m_casts[m_any->type_id ()].add_overload (fn);
1867 
1868  // cast scalar <- any
1870  m_any);
1871  m_casts[m_scalar->type_id ()].add_overload (fn);
1872 
1873  // cast any <- complex
1875  m_complex);
1876  m_casts[m_any->type_id ()].add_overload (fn);
1877 
1878  // cast complex <- any
1880  m_any);
1881  m_casts[m_complex->type_id ()].add_overload (fn);
1882 
1883  // cast complex <- scalar
1884  fn = create_internal ("octave_jit_cast_complex_scalar", m_complex,
1885  m_scalar);
1886  body = fn.new_block ();
1887  m_builder.SetInsertPoint (body);
1888  {
1889  llvm::Value *zero = llvm::ConstantFP::get (m_scalar_t, 0);
1890  fn.do_return (m_builder, complex_new (fn.argument (m_builder, 0), zero));
1891  }
1892  m_casts[m_complex->type_id ()].add_overload (fn);
1893 
1894  // cast scalar <- complex
1895  fn = create_internal ("octave_jit_cast_scalar_complex", m_scalar,
1896  m_complex);
1897  body = fn.new_block ();
1898  m_builder.SetInsertPoint (body);
1900  m_casts[m_scalar->type_id ()].add_overload (fn);
1901 
1902  // cast any <- any
1903  fn = create_identity (m_any);
1904  m_casts[m_any->type_id ()].add_overload (fn);
1905 
1906  // cast scalar <- scalar
1907  fn = create_identity (m_scalar);
1908  m_casts[m_scalar->type_id ()].add_overload (fn);
1909 
1910  // cast complex <- complex
1911  fn = create_identity (m_complex);
1912  m_casts[m_complex->type_id ()].add_overload (fn);
1913 
1914  // -------------------- builtin functions --------------------
1915  add_builtin ("#unknown_function");
1916  m_unknown_function = m_builtins["#unknown_function"];
1917 
1918  add_builtin ("sin");
1919  register_intrinsic ("sin", llvm::Intrinsic::sin, m_scalar, m_scalar);
1921 
1922  add_builtin ("cos");
1923  register_intrinsic ("cos", llvm::Intrinsic::cos, m_scalar, m_scalar);
1925 
1926  add_builtin ("exp");
1927  register_intrinsic ("exp", llvm::Intrinsic::exp, m_scalar, m_scalar);
1929 
1930  add_builtin ("balance");
1931  register_generic ("balance", m_matrix, m_matrix);
1932 
1933  add_builtin ("cond");
1934  register_generic ("cond", m_scalar, m_matrix);
1935 
1936  add_builtin ("det");
1938 
1939  add_builtin ("norm");
1940  register_generic ("norm", m_scalar, m_matrix);
1941 
1942  add_builtin ("rand");
1943  register_generic ("rand", m_matrix, m_scalar);
1944  register_generic ("rand", m_matrix, std::vector<jit_type *> (2, m_scalar));
1945 
1946  add_builtin ("magic");
1947  register_generic ("magic", m_matrix, m_scalar);
1948  register_generic ("magic", m_matrix,
1949  std::vector<jit_type *> (2, m_scalar));
1950 
1951  add_builtin ("eye");
1953  register_generic ("eye", m_matrix, std::vector<jit_type *> (2, m_scalar));
1954 
1955  add_builtin ("mod");
1956  register_generic ("mod", m_scalar, std::vector<jit_type *> (2, m_scalar));
1957 
1958  // m_casts.resize (m_next_id + 1);
1959  jit_function any_id = create_identity (m_any);
1961  m_any, m_any);
1962 
1963  jit_function release_any = m_release_fn.overload (m_any);
1964 
1965  std::vector<jit_type *> args;
1966  args.resize (1);
1967 
1968  for (auto iter = m_builtins.begin ();
1969  iter != m_builtins.end (); ++iter)
1970  {
1971  jit_type *btype = iter->second;
1972  args[0] = btype;
1973 
1974  m_grab_fn.add_overload (jit_function (grab_any, btype, args));
1975  m_release_fn.add_overload (jit_function (release_any, 0, args));
1976  m_casts[m_any->type_id ()].add_overload (jit_function (any_id, m_any,
1977  args));
1978 
1979  args[0] = m_any;
1980  m_casts[btype->type_id ()].add_overload (jit_function (any_id, btype,
1981  args));
1982  }
1983 
1985 
1986  s_in_construction = false;
1987  }
1988 
1989  // create a function with an external calling convention
1990  // forces the function pointer to be specified
1991  template <typename fn_ptr_type> jit_function
1993  const llvm::Twine& name,
1994  jit_type *ret,
1995  const std::vector<jit_type *>& args) const
1996  {
1998  name, ret, args);
1999 
2000  m_base_jit_module->add_global_mapping (retval.to_llvm (), fn);
2001 
2002  return retval;
2003  }
2004 
2005  jit_type*
2007  jit_type *parent,
2008  llvm::Type *llvm_type,
2009  bool skip_paren)
2010  {
2011  // FIXME: Currently our types do *not* form a lattice
2012  assert ((name == "any") || (name == "any_ptr")
2013  || (name == "scalar_ptr") || (parent != nullptr));
2014 
2015  jit_type *ret = new jit_type (name, parent, llvm_type, skip_paren,
2016  m_next_id++);
2017  m_id_to_type.push_back (ret);
2018 
2019  m_casts.push_back (jit_operation ("(" + name + ")"));
2020  m_identities.push_back (jit_function ());
2021 
2022  return ret;
2023  }
2024 
2025  jit_type*
2026  jit_typeinfo::do_get_intN (size_t nbits) const
2027  {
2028  std::map<size_t, jit_type *>::const_iterator iter = m_ints.find (nbits);
2029  if (iter != m_ints.end ())
2030  return iter->second;
2031 
2032  throw jit_fail_exception ("No such integer type");
2033  }
2034 
2035  const jit_function&
2037  {
2038  jit_const_index *ccount = dynamic_cast<jit_const_index *> (count);
2039  if (ccount && ccount->value () == 1)
2040  return m_end1_fn.overload (value->type (), idx->type (), count->type ());
2041 
2042  return m_end_fn.overload (value->type (), idx->type (), count->type ());
2043  }
2044 
2045  void
2047  {
2048  std::stringstream name;
2049  name << "octave_jit_print_" << ty->name ();
2050 
2051  jit_function fn = create_external (fptr, name.str (), nullptr,
2052  do_get_intN (8), ty);
2053 
2054  m_print_fn.add_overload (fn);
2055  }
2056 
2057  // FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp
2058  void
2059  jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op)
2060  {
2061  std::stringstream fname;
2062  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
2063  fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op)
2064  << '_' << ty->name ();
2065 
2066  jit_function fn = create_internal (fname.str (), ty, ty, ty);
2067  llvm::BasicBlock *block = fn.new_block ();
2068  m_builder.SetInsertPoint (block);
2069  llvm::Instruction::BinaryOps temp
2070  = static_cast<llvm::Instruction::BinaryOps>(llvm_op);
2071 
2072  llvm::Value *ret = m_builder.CreateBinOp (temp, fn.argument (m_builder, 0),
2073  fn.argument (m_builder, 1));
2074  fn.do_return (m_builder, ret);
2075  m_binary_ops[op].add_overload (fn);
2076  }
2077 
2078  void
2079  jit_typeinfo::add_binary_icmp (jit_type *ty, int op, int llvm_op)
2080  {
2081  std::stringstream fname;
2082  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
2083  fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
2084  << '_' << ty->name ();
2085 
2086  jit_function fn = create_internal (fname.str (), m_boolean, ty, ty);
2087  llvm::BasicBlock *block = fn.new_block ();
2088  m_builder.SetInsertPoint (block);
2089  llvm::CmpInst::Predicate temp
2090  = static_cast<llvm::CmpInst::Predicate>(llvm_op);
2091  llvm::Value *ret = m_builder.CreateICmp (temp, fn.argument (m_builder, 0),
2092  fn.argument (m_builder, 1));
2093  fn.do_return (m_builder, ret);
2094  m_binary_ops[op].add_overload (fn);
2095  }
2096 
2097  void
2098  jit_typeinfo::add_binary_fcmp (jit_type *ty, int op, int llvm_op)
2099  {
2100  std::stringstream fname;
2101  octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op);
2102  fname << "octave_jit" << octave_value::binary_op_as_string (ov_op)
2103  << '_' << ty->name ();
2104 
2105  jit_function fn = create_internal (fname.str (), m_boolean, ty, ty);
2106  llvm::BasicBlock *block = fn.new_block ();
2107  m_builder.SetInsertPoint (block);
2108  llvm::CmpInst::Predicate temp
2109  = static_cast<llvm::CmpInst::Predicate>(llvm_op);
2110  llvm::Value *ret = m_builder.CreateFCmp (temp, fn.argument (m_builder, 0),
2111  fn.argument (m_builder, 1));
2112  fn.do_return (m_builder, ret);
2113  m_binary_ops[op].add_overload (fn);
2114  }
2115 
2116  jit_function
2118  {
2119  size_t id = type->type_id ();
2120  if (id >= m_identities.size ())
2121  m_identities.resize (id + 1);
2122 
2123  if (! m_identities[id].valid ())
2124  {
2125  std::stringstream name;
2126  name << "id_" << type->name ();
2127 
2128  jit_function fn = create_internal (name.str (), type, type);
2129  llvm::BasicBlock *body = fn.new_block ();
2130  m_builder.SetInsertPoint (body);
2131  fn.do_return (m_builder, fn.argument (m_builder, 0));
2132  return m_identities[id] = fn;
2133  }
2134 
2135  return m_identities[id];
2136  }
2137 
2138  llvm::Value *
2140  {
2141  return abuilder.CreateLoad (m_lerror_state);
2142  }
2143 
2144  llvm::Value *
2146  {
2147  llvm::LoadInst *val = abuilder.CreateLoad (m_loctave_interrupt_state);
2148  val->setVolatile (true);
2149  return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0));
2150  }
2151 
2152  void
2153  jit_typeinfo::add_builtin (const std::string& name)
2154  {
2155  jit_type *btype = do_register_new_type (name, m_any, m_any_t, true);
2156  m_builtins[name] = btype;
2157 
2158  octave_builtin *ov_builtin = find_builtin (name);
2159  if (ov_builtin)
2160  ov_builtin->stash_jit (*btype);
2161  }
2162 
2163  void
2164  jit_typeinfo::register_intrinsic (const std::string& name, size_t iid,
2165  jit_type *result,
2166  const std::vector<jit_type *>& args)
2167  {
2168  jit_type *builtin_type = m_builtins[name];
2169  size_t nargs = args.size ();
2170  std::vector<llvm::Type*> llvm_args (nargs);
2171  for (size_t i = 0; i < nargs; ++i)
2172  llvm_args[i] = args[i]->to_llvm ();
2173 
2174  llvm::Function *ifun = m_base_jit_module->
2175  get_intrinsic_declaration (iid, llvm_args);
2176 
2177  std::stringstream fn_name;
2178  fn_name << "octave_jit_" << name;
2179 
2180  std::vector<jit_type *> args1 (nargs + 1);
2181  args1[0] = builtin_type;
2182  std::copy (args.begin (), args.end (), args1.begin () + 1);
2183 
2184  // The first argument will be the Octave function, but we already know that
2185  // the function call is the equivalent of the intrinsic, so we ignore it
2186  // and call the intrinsic with the remaining arguments.
2187  jit_function fn = create_internal (fn_name.str (), result, args1);
2188  llvm::BasicBlock *body = fn.new_block ();
2189  m_builder.SetInsertPoint (body);
2190 
2191  llvm::SmallVector<llvm::Value *, 5> fargs (nargs);
2192  for (size_t i = 0; i < nargs; ++i)
2193  fargs[i] = fn.argument (m_builder, i + 1);
2194 
2195  llvm::Value *ret = m_builder.CreateCall (ifun, fargs);
2196  fn.do_return (m_builder, ret);
2198  }
2199 
2200  octave_builtin *
2201  jit_typeinfo::find_builtin (const std::string& name)
2202  {
2203  symbol_table& symtab = __get_symbol_table__ ("jit_typeinfo::find_builtin");
2204 
2205  // FIXME: Finalize what we want to store in octave_builtin, then add
2206  // functions to access these values in octave_value
2207  octave_value ov_builtin = symtab.builtin_find (name);
2208  return dynamic_cast<octave_builtin *> (ov_builtin.internal_rep ());
2209  }
2210 
2211  void
2212  jit_typeinfo::register_generic (const std::string& name, jit_type *result,
2213  const std::vector<jit_type *>& args)
2214  {
2215  octave_builtin *builtin = find_builtin (name);
2216  if (! builtin)
2217  return;
2218 
2219  std::vector<jit_type *> fn_args (args.size () + 1);
2220  fn_args[0] = m_builtins[name];
2221  std::copy (args.begin (), args.end (), fn_args.begin () + 1);
2222  jit_function fn = create_internal (name, result, fn_args);
2223  fn.mark_can_error ();
2224  llvm::BasicBlock *block = fn.new_block ();
2225  m_builder.SetInsertPoint (block);
2226  llvm::ArrayType *array_t = llvm::ArrayType::get (m_any_t, args.size ());
2227  llvm::Value *array = llvm::UndefValue::get (array_t);
2228  for (size_t i = 0; i < args.size (); ++i)
2229  {
2230  llvm::Value *arg = fn.argument (m_builder, i + 1);
2231  jit_function agrab = m_grab_fn.overload (args[i]);
2232  if (agrab.valid ())
2233  arg = agrab.call (m_builder, arg);
2234  jit_function acast = do_cast (m_any, args[i]);
2235  array = m_builder.CreateInsertValue (array,
2236  acast.call (m_builder, arg), i);
2237  }
2238 
2239  llvm::Value *array_mem = m_builder.CreateAlloca (array_t);
2240  m_builder.CreateStore (array, array_mem);
2241  array = m_builder.CreateBitCast (array_mem, m_any_t->getPointerTo ());
2242 
2243  jit_type *jintTy = do_get_intN (sizeof (octave_builtin::fcn) * 8);
2244  llvm::Type *intTy = jintTy->to_llvm ();
2245  size_t fcn_int = reinterpret_cast<size_t> (builtin->function ());
2246  llvm::Value *fcn = llvm::ConstantInt::get (intTy, fcn_int);
2247  llvm::Value *nargin = llvm::ConstantInt::get (intTy, args.size ());
2248  size_t result_int = reinterpret_cast<size_t> (result);
2249  llvm::Value *res_llvm = llvm::ConstantInt::get (intTy, result_int);
2250  llvm::Value *ret = m_any_call.call (m_builder, fcn, nargin, array,
2251  res_llvm);
2252 
2253  jit_function cast_result = do_cast (result, m_any);
2254  fn.do_return (m_builder, cast_result.call (m_builder, ret));
2256  }
2257 
2258  jit_function
2260  {
2261  jit_function ret = create_internal (fn.name () + "_reverse",
2262  fn.result (), fn.argument_type (1),
2263  fn.argument_type (0));
2264  if (fn.can_error ())
2265  ret.mark_can_error ();
2266 
2267  llvm::BasicBlock *body = ret.new_block ();
2268  m_builder.SetInsertPoint (body);
2269  llvm::Value *result = fn.call (m_builder, ret.argument (m_builder, 1),
2270  ret.argument (m_builder, 0));
2271  if (ret.result ())
2272  ret.do_return (m_builder, result);
2273  else
2274  ret.do_return (m_builder);
2275 
2276  return ret;
2277  }
2278 
2279  llvm::Value *
2280  jit_typeinfo::do_pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) const
2281  {
2282  llvm::Value *real = bld.CreateExtractValue (cplx, 0);
2283  llvm::Value *imag = bld.CreateExtractValue (cplx, 1);
2284  llvm::Value *ret = llvm::UndefValue::get (m_complex_ret);
2285 
2286  unsigned int re_idx[] = {0, 0};
2287  unsigned int im_idx[] = {0, 1};
2288  ret = bld.CreateInsertValue (ret, real, re_idx);
2289  return bld.CreateInsertValue (ret, imag, im_idx);
2290  }
2291 
2292  llvm::Value *
2294  {
2295  unsigned int re_idx[] = {0, 0};
2296  unsigned int im_idx[] = {0, 1};
2297 
2298  llvm::Type *m_complex_t = get_complex ()->to_llvm ();
2299  llvm::Value *real = bld.CreateExtractValue (result, re_idx);
2300  llvm::Value *imag = bld.CreateExtractValue (result, im_idx);
2301  llvm::Value *ret = llvm::UndefValue::get (m_complex_t);
2302 
2303  ret = bld.CreateInsertValue (ret, real, 0);
2304  return bld.CreateInsertValue (ret, imag, 1);
2305  }
2306 
2307  llvm::Value *
2308  jit_typeinfo::complex_real (llvm::Value *cx)
2309  {
2310  return m_builder.CreateExtractValue (cx, 0);
2311  }
2312 
2313  llvm::Value *
2314  jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real)
2315  {
2316  return m_builder.CreateInsertValue (cx, real, 0);
2317  }
2318 
2319  llvm::Value *
2320  jit_typeinfo::complex_imag (llvm::Value *cx)
2321  {
2322  return m_builder.CreateExtractValue (cx, 1);
2323  }
2324 
2325  llvm::Value *
2326  jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag)
2327  {
2328  return m_builder.CreateInsertValue (cx, imag, 1);
2329  }
2330 
2331  llvm::Value *
2332  jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag)
2333  {
2334  llvm::Value *ret = llvm::UndefValue::get (m_complex->to_llvm ());
2335  ret = complex_real (ret, real);
2336  return complex_imag (ret, imag);
2337  }
2338 
2339  jit_type *
2341  {
2342  if (ov.is_function ())
2343  {
2344  // FIXME: This is ugly, we need to finalize how we want to do this,
2345  // then have octave_value fully support the needed functionality
2346  octave_builtin *builtin
2347  = dynamic_cast<octave_builtin *> (ov.internal_rep ());
2348  return builtin && builtin->to_jit () ? builtin->to_jit ()
2350  }
2351 
2352  if (ov.is_range ())
2353  return m_range;
2354 
2355  if (ov.is_double_type () && ! ov.iscomplex ())
2356  {
2357  if (ov.is_real_scalar ())
2358  return m_scalar;
2359 
2360  if (ov.is_matrix_type ())
2361  return m_matrix;
2362  }
2363 
2364  if (ov.is_complex_scalar ())
2365  {
2366  Complex cv = ov.complex_value ();
2367 
2368  // We don't really represent complex values, instead we represent
2369  // complex_or_scalar. If the imag value is zero, we assume a scalar.
2370  if (cv.imag () != 0)
2371  return m_complex;
2372  }
2373 
2374  return m_any;
2375  }
2376 }
2377 
2378 #endif
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:128
void resize1(octave_idx_type n, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:898
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
void assign(const idx_vector &i, const Array< T > &rhs, const T &rfv)
Indexed assignment (always with resize & fill).
Definition: Array.cc:1116
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
T * jit_slice_data(void) const
Size of the specified dimension.
Definition: Array.h:845
int jit_ref_count(void)
WARNING: Only call these functions from jit.
Definition: Array.h:843
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
Definition: dMatrix.h:42
Definition: Range.h:40
octave_idx_type numel(void) const
Definition: Range.h:87
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
PASS_T value(void) const
Definition: jit-ir.h:536
bool valid(void) const
Definition: jit-typeinfo.h:262
llvm::Value * call(llvm::IRBuilderD &builder, const arg_vec &in_args=arg_vec()) const
std::string name(void) const
jit_type * argument_type(size_t idx) const
Definition: jit-typeinfo.h:329
bool can_error(void) const
Definition: jit-typeinfo.h:323
jit_convention::type m_call_conv
Definition: jit-typeinfo.h:343
jit_type * result(void) const
Definition: jit-typeinfo.h:327
std::vector< jit_type * > m_args
Definition: jit-typeinfo.h:342
llvm::BasicBlock * new_block(const std::string &aname="body", llvm::BasicBlock *insert_before=nullptr)
bool sret(void) const
Definition: jit-typeinfo.h:321
void mark_can_error(void)
Definition: jit-typeinfo.h:325
const jit_module * m_module
Definition: jit-typeinfo.h:339
llvm::Value * argument(llvm::IRBuilderD &builder, size_t idx) const
llvm::Function * m_llvm_function
Definition: jit-typeinfo.h:340
llvm::Function * to_llvm(void) const
Definition: jit-typeinfo.h:318
void do_return(llvm::IRBuilderD &builder, llvm::Value *rval=nullptr, bool verify=true)
virtual jit_function * generate(const signature_vec &types) const
const jit_typeinfo & m_typeinfo
Definition: jit-typeinfo.h:463
llvm::Value * create_arg_array(llvm::IRBuilderD &builder, const jit_function &fn, size_t start_idx, size_t end_idx) const
llvm::Function * create_llvm_function(llvm::FunctionType *ftype, const llvm::Twine &name) const
Definition: pt-jit.cc:2359
void add_global_mapping(const llvm::GlobalValue *gv, ptr_type p) const
Definition: pt-jit.h:557
void finalizeObject(void)
Definition: pt-jit.cc:2475
llvm::GlobalVariable * create_global_variable(llvm::Type *type, bool is_constant, const llvm::Twine &name) const
Definition: pt-jit.cc:2381
virtual ~jit_operation(void)
const jit_function & do_generate(const signature_vec &types) const
std::vector< jit_type * > signature_vec
Definition: jit-typeinfo.h:359
generated_map m_generated
Definition: jit-typeinfo.h:435
virtual jit_function * generate(const signature_vec &types) const
std::vector< Array< jit_function > > m_overloads
Definition: jit-typeinfo.h:437
Array< octave_idx_type > to_idx(const signature_vec &types) const
void add_overload(const jit_function &func)
Definition: jit-typeinfo.h:363
const jit_function & overload(const signature_vec &types) const
jit_function * generate_matrix(const signature_vec &types) const
jit_paren_subsasgn(const jit_typeinfo &ti)
jit_function * m_paren_scalar
Definition: jit-typeinfo.h:501
jit_paren_subsref(const jit_typeinfo &ti)
jit_function * m_paren_scalar
Definition: jit-typeinfo.h:482
virtual jit_function * generate_matrix(const signature_vec &types) const
size_t depth(void) const
Definition: jit-typeinfo.h:165
llvm::Type * to_llvm(void) const
Definition: jit-typeinfo.h:160
convert_fn m_pack[jit_convention::length]
Definition: jit-typeinfo.h:220
int type_id(void) const
Definition: jit-typeinfo.h:154
bool pointer_arg(jit_convention::type cc) const
Definition: jit-typeinfo.h:183
convert_fn pack(jit_convention::type cc)
Definition: jit-typeinfo.h:191
llvm::Type * packed_type(jit_convention::type cc)
Definition: jit-typeinfo.h:202
bool m_sret[jit_convention::length]
Definition: jit-typeinfo.h:217
llvm::Type * m_llvm_type
Definition: jit-typeinfo.h:212
void set_unpack(jit_convention::type cc, convert_fn fn)
Definition: jit-typeinfo.h:198
llvm::Type * to_llvm_arg(void) const
jit_type(const std::string &aname, jit_type *aparent, llvm::Type *allvm_type, bool askip_paren, int aid)
jit_type * parent(void) const
Definition: jit-typeinfo.h:157
void set_pack(jit_convention::type cc, convert_fn fn)
Definition: jit-typeinfo.h:193
llvm::Value *(* convert_fn)(llvm::IRBuilderD &, llvm::Value *)
Definition: jit-typeinfo.h:145
void mark_pointer_arg(jit_convention::type cc)
Definition: jit-typeinfo.h:185
llvm::Type * m_packed_type[jit_convention::length]
Definition: jit-typeinfo.h:223
void set_packed_type(jit_convention::type cc, llvm::Type *ty)
Definition: jit-typeinfo.h:205
convert_fn unpack(jit_convention::type cc)
Definition: jit-typeinfo.h:196
bool m_pointer_arg[jit_convention::length]
Definition: jit-typeinfo.h:218
void mark_sret(jit_convention::type cc)
Definition: jit-typeinfo.h:177
const std::string & name(void) const
Definition: jit-typeinfo.h:151
convert_fn m_unpack[jit_convention::length]
Definition: jit-typeinfo.h:221
jit_operation m_logically_true_fn
Definition: jit-typeinfo.h:917
static llvm::Type * get_scalar_llvm(void)
Definition: jit-typeinfo.h:567
llvm::Type * m_string_t
Definition: jit-typeinfo.h:580
llvm::Type * m_index_t
Definition: jit-typeinfo.h:578
std::map< std::string, jit_type * > m_builtins
Definition: jit-typeinfo.h:906
llvm::Type * m_sig_atomic_type
Definition: jit-typeinfo.h:904
static bool s_in_construction
Definition: jit-typeinfo.h:519
jit_operation m_grab_fn
Definition: jit-typeinfo.h:910
llvm::StructType * m_complex_ret
Definition: jit-typeinfo.h:603
static llvm::Value * pack_complex(llvm::IRBuilderD &bld, llvm::Value *cplx)
Definition: jit-typeinfo.h:744
void add_binary_op(jit_type *ty, int op, int llvm_op)
void add_binary_icmp(jit_type *ty, int op, int llvm_op)
static jit_type * get_scalar(void)
Definition: jit-typeinfo.h:548
jit_type * do_get_intN(size_t nbits) const
llvm::IRBuilderD * m_builder_ptr
Definition: jit-typeinfo.h:933
jit_operation m_for_index_fn
Definition: jit-typeinfo.h:916
void add_print(jit_type *ty, void *fptr)
llvm::Value * do_insert_error_check(llvm::IRBuilderD &bld)
jit_operation m_end_fn
Definition: jit-typeinfo.h:920
jit_type * m_unknown_function
Definition: jit-typeinfo.h:599
void add_binary_fcmp(jit_type *ty, int op, int llvm_op)
llvm::Value * complex_new(llvm::Value *real, llvm::Value *imag)
static jit_typeinfo & instance(void)
std::vector< jit_operation > m_unary_ops
Definition: jit-typeinfo.h:909
jit_type * do_type_of(const octave_value &ov) const
jit_operation m_for_init_fn
Definition: jit-typeinfo.h:914
void register_intrinsic(const std::string &name, size_t id, jit_type *result, jit_type *arg0)
Definition: jit-typeinfo.h:861
const jit_function & do_end(jit_value *value, jit_value *index, jit_value *count)
jit_function create_internal(const llvm::Twine &name, jit_type *ret, const signature_vec &args=signature_vec()) const
Definition: jit-typeinfo.h:826
jit_operation m_for_check_fn
Definition: jit-typeinfo.h:915
llvm::Type * m_scalar_t
Definition: jit-typeinfo.h:579
llvm::Type * m_bool_t
Definition: jit-typeinfo.h:576
static jit_type * get_matrix(void)
Definition: jit-typeinfo.h:546
jit_operation m_release_fn
Definition: jit-typeinfo.h:911
static jit_type * get_complex(void)
Definition: jit-typeinfo.h:562
static llvm::Value * unpack_complex(llvm::IRBuilderD &bld, llvm::Value *result)
llvm::Value * do_insert_interrupt_check(llvm::IRBuilderD &bld)
llvm::Type * m_complex_t
Definition: jit-typeinfo.h:577
llvm::GlobalVariable * m_loctave_interrupt_state
Definition: jit-typeinfo.h:902
llvm::StructType * m_range_t
Definition: jit-typeinfo.h:582
jit_function create_external(T fn, const llvm::Twine &name, jit_type *ret, const signature_vec &args=signature_vec()) const
llvm::Value * complex_imag(llvm::Value *cx)
const jit_operation & do_cast(jit_type *to)
Definition: jit-typeinfo.h:768
llvm::Value * do_pack_complex(llvm::IRBuilderD &bld, llvm::Value *cplx) const
jit_operation m_end1_fn
Definition: jit-typeinfo.h:919
void register_generic(const std::string &name, jit_type *result, jit_type *arg0)
Definition: jit-typeinfo.h:871
jit_type * m_scalar_ptr
Definition: jit-typeinfo.h:597
jit_module * m_base_jit_module
Definition: jit-typeinfo.h:931
std::vector< jit_operation > m_casts
Definition: jit-typeinfo.h:926
std::vector< jit_function > m_identities
Definition: jit-typeinfo.h:929
jit_function mirror_binary(const jit_function &fn)
std::map< size_t, jit_type * > m_ints
Definition: jit-typeinfo.h:610
llvm::IRBuilderD & m_builder
Definition: jit-typeinfo.h:934
jit_paren_subsref paren_subsref_fn
Definition: jit-typeinfo.h:624
llvm::GlobalVariable * m_lerror_state
Definition: jit-typeinfo.h:901
jit_operation m_print_fn
Definition: jit-typeinfo.h:913
jit_operation m_create_undef_fn
Definition: jit-typeinfo.h:921
void add_builtin(const std::string &name)
jit_paren_subsasgn paren_subsasgn_fn
Definition: jit-typeinfo.h:625
jit_operation m_destroy_fn
Definition: jit-typeinfo.h:912
llvm::Type * m_any_t
Definition: jit-typeinfo.h:575
llvm::Value * complex_real(llvm::Value *cx)
jit_function create_identity(jit_type *type)
llvm::StructType * m_matrix_t
Definition: jit-typeinfo.h:583
std::vector< jit_type * > m_id_to_type
Definition: jit-typeinfo.h:534
jit_operation m_make_range_fn
Definition: jit-typeinfo.h:918
jit_function m_any_call
Definition: jit-typeinfo.h:923
jit_type * do_register_new_type(const std::string &name, jit_type *parent, llvm::Type *llvm_type, bool skip_paren=false)
std::vector< jit_operation > m_binary_ops
Definition: jit-typeinfo.h:908
octave_builtin * find_builtin(const std::string &name)
jit_type * type(void) const
Definition: jit-ir.h:211
octave_value builtin_find(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:190
static llvm::LLVMContext llvm_context
Definition: pt-jit.h:389
virtual void print_with_name(std::ostream &output_buf, const std::string &name, bool print_padding=true)
Definition: ov-base.cc:436
void release(void)
Definition: ov-base.h:824
void grab(void)
Definition: ov-base.h:817
virtual NDArray array_value(bool=false) const
Definition: ov-base.cc:553
virtual double double_value(bool=false) const
Definition: ov-base.cc:523
virtual Range range_value(void) const
Definition: ov-base.cc:815
virtual Complex complex_value(bool=false) const
Definition: ov-base.cc:565
octave::jit_type * to_jit(void) const
Definition: ov-builtin.cc:91
octave_value_list(* fcn)(const octave_value_list &, int)
Definition: ov-builtin.h:63
void stash_jit(octave::jit_type &type)
Definition: ov-builtin.cc:97
fcn function(void) const
Definition: ov-builtin.cc:103
octave_value & xelem(octave_idx_type i)
Definition: ovl.h:171
bool empty(void) const
Definition: ovl.h:115
octave_idx_type length(void) const
Definition: ovl.h:113
bool is_function(void) const
Definition: ov.h:730
static std::string binary_op_as_string(binary_op)
Definition: ov.cc:178
void print_with_name(std::ostream &os, const std::string &name) const
Definition: ov.h:1239
unary_op
Definition: ov.h:83
@ op_hermitian
Definition: ov.h:88
@ num_unary_ops
Definition: ov.h:91
@ op_uminus
Definition: ov.h:86
@ op_transpose
Definition: ov.h:87
@ op_uplus
Definition: ov.h:85
@ op_incr
Definition: ov.h:89
@ op_decr
Definition: ov.h:90
Complex complex_value(bool frc_str_conv=false) const
Definition: ov.h:818
octave_base_value * internal_rep(void) const
Definition: ov.h:1321
bool is_double_type(void) const
Definition: ov.h:648
static std::string unary_op_as_string(unary_op)
Definition: ov.cc:122
bool is_matrix_type(void) const
Definition: ov.h:700
binary_op
Definition: ov.h:96
@ op_ldiv
Definition: ov.h:102
@ op_ne
Definition: ov.h:108
@ op_el_or
Definition: ov.h:114
@ op_el_ldiv
Definition: ov.h:112
@ op_pow
Definition: ov.h:101
@ op_ge
Definition: ov.h:106
@ num_binary_ops
Definition: ov.h:116
@ op_div
Definition: ov.h:100
@ op_el_pow
Definition: ov.h:111
@ op_mul
Definition: ov.h:99
@ op_add
Definition: ov.h:97
@ op_sub
Definition: ov.h:98
@ op_el_mul
Definition: ov.h:109
@ op_le
Definition: ov.h:104
@ op_lt
Definition: ov.h:103
@ op_gt
Definition: ov.h:107
@ op_eq
Definition: ov.h:105
@ op_el_and
Definition: ov.h:113
@ op_el_div
Definition: ov.h:110
bool is_range(void) const
Definition: ov.h:602
bool is_real_scalar(void) const
Definition: ov.h:566
bool is_undefined(void) const
Definition: ov.h:554
bool iscomplex(void) const
Definition: ov.h:694
bool is_complex_scalar(void) const
Definition: ov.h:572
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:104
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
int error_state
Definition: error.cc:2193
void error(const char *fmt,...)
Definition: error.cc:968
#define panic_impossible()
Definition: error.h:380
static int convert(int x, int ibase, int obase)
Definition: file-io.cc:3032
QString name
#define JIT_FN(fn)
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
Definition: jit-util.h:45
IRBuilder< true, ConstantFolder, IRBuilderDefaultInserter< true > > IRBuilderD
Definition: jit-util.h:80
T x_nint(T x)
Definition: lo-mappers.h:262
FloatComplex(* fptr)(const FloatComplex &, float, int, octave_idx_type &)
Definition: lo-specfun.cc:1128
octave_idx_type octave_jit_compute_nelem(double base, double limit, double inc)
void octave_jit_print_any(const char *name, octave_base_value *obv)
Definition: jit-typeinfo.cc:91
void octave_jit_gindex_range(int nd, int dim, octave_idx_type iext, octave_idx_type ext)
std::ostream & operator<<(std::ostream &os, const jit_block_list &blocks)
Definition: jit-ir.cc:134
void err_invalid_index(const std::string &idx, octave_idx_type nd, octave_idx_type dim, const std::string &)
void octave_jit_err_nan_to_logical_conversion(void)
jit_type * jit_type_join(jit_type *lhs, jit_type *rhs)
jit_range octave_jit_cast_range_any(octave_base_value *obv)
Complex octave_jit_pow_complex_scalar(Complex lhs, double rhs)
void octave_jit_release_any(octave_base_value *obv)
jit_matrix octave_jit_cast_matrix_any(octave_base_value *obv)
Complex octave_jit_pow_complex_complex(Complex lhs, Complex rhs)
Complex octave_jit_pow_scalar_scalar(double lhs, double rhs)
octave_base_value * octave_jit_grab_any(octave_base_value *obv)
Complex octave_jit_complex_div(Complex lhs, Complex rhs)
static int xisint(double x)
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:80
octave_base_value * octave_jit_cast_any_matrix(jit_matrix *m)
jit_matrix octave_jit_paren_scalar_subsasgn(jit_matrix *mat, double *indices, octave_idx_type idx_count, double value)
std::ostream & jit_print(std::ostream &os, jit_value *avalue)
Definition: jit-ir.cc:198
void err_nan_to_logical_conversion(void)
void err_index_out_of_range(int nd, int dim, octave_idx_type idx, octave_idx_type ext, const dim_vector &dv)
void octave_jit_print_matrix(jit_matrix *m)
octave_base_value * octave_jit_create_undef(void)
octave_base_value * octave_jit_cast_any_complex(Complex c)
static OCTAVE_NORETURN void err_bad_result(void)
double octave_jit_paren_scalar(jit_matrix *mat, double *indices, octave_idx_type idx_count)
octave_base_value * octave_jit_cast_any_scalar(double value)
double octave_jit_cast_scalar_any(octave_base_value *obv)
Complex octave_jit_cast_complex_any(octave_base_value *obv)
jit_array< NDArray, double > jit_matrix
Definition: jit-typeinfo.h:115
void octave_jit_print_scalar(const char *name, double value)
Definition: jit-typeinfo.cc:97
octave_base_value * octave_jit_binary_any_any(octave_value::binary_op op, octave_base_value *lhs, octave_base_value *rhs)
jit_matrix octave_jit_paren_subsasgn_matrix_range(jit_matrix *mat, jit_range *index, double value)
symbol_table & __get_symbol_table__(const std::string &who)
Complex octave_jit_complex_mul(Complex lhs, Complex rhs)
double octave_jit_end_matrix(jit_matrix *mat, octave_idx_type idx, octave_idx_type count)
static llvm::IRBuilder builder(tree_jit::llvm_context)
jit_matrix octave_jit_grab_matrix(jit_matrix *m)
Complex octave_jit_pow_scalar_complex(double lhs, Complex rhs)
static void make_indices(double *indices, octave_idx_type idx_count, Array< idx_vector > &result)
void octave_jit_ginvalid_index(void)
octave_base_value * octave_jit_call(octave_builtin::fcn fn, size_t nargin, octave_base_value **argin, jit_type *result_type)
jit_matrix octave_jit_paren_subsasgn_impl(jit_matrix *mat, octave_idx_type index, double value)
octave_base_value * octave_jit_cast_any_range(jit_range *rng)
void octave_jit_release_matrix(jit_matrix *m)
std::complex< double > Complex
Definition: oct-cmplx.h:33
octave_int< T > pow(const octave_int< T > &a, const octave_int< T > &b)
T::size_type numel(const T &str)
Definition: oct-string.cc:71
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
static bool scalar(const dim_vector &dims)
Definition: ov-struct.cc:669
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
OCTINTERP_API octave_value do_binary_op(octave::type_info &ti, octave_value::binary_op op, const octave_value &a, const octave_value &b)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
#define octave_stdout
Definition: pager.h:313
sig_atomic_t octave_interrupt_state
Definition: quit.cc:38
octave_idx_type * m_dimensions
Definition: jit-typeinfo.h:110
octave_idx_type m_slice_len
Definition: jit-typeinfo.h:109
void update(void)
Definition: jit-typeinfo.h:87
bool operator()(const signature_vec *lhs, const signature_vec *rhs) const
bool all_elements_are_ints(void) const
octave_idx_type m_nelem
Definition: jit-typeinfo.h:70
F77_RET_T len
Definition: xerbla.cc:61