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