GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
pt-jit.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 #define __STDC_LIMIT_MACROS
27 #define __STDC_CONSTANT_MACROS
28 
29 #if defined (HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
32 
33 #include <sstream>
34 #include <string>
35 
36 #include "bp-table.h"
37 #include "defun.h"
38 #include "errwarn.h"
39 #include "ov.h"
40 #include "pager.h"
41 #include "pt-all.h"
42 #include "pt-jit.h"
43 #include "sighandlers.h"
44 #include "symtab.h"
45 #include "variables.h"
46 #include "interpreter-private.h"
47 
48 // Programming Note: As of hg id 2b2c8ac44cd2, this file builds with
49 // LLVM 3.8 but not with 3.9 (or probably any later version).
50 
51 #if defined (HAVE_LLVM)
52 
53 #include <llvm/Analysis/CallGraph.h>
54 #include <llvm/Analysis/Passes.h>
55 
56 #if defined (HAVE_LLVM_IR_VERIFIER_H)
57 # include <llvm/IR/Verifier.h>
58 #else
59 # include <llvm/Analysis/Verifier.h>
60 #endif
61 
62 #if defined (HAVE_LLVM_ANALYSIS_BASICALIASANALYSIS_H)
63 // In LLVM 3.8.x and later, we use createBasicAAWrapperPass from:
64 # include <llvm/Analysis/BasicAliasAnalysis.h>
65 #endif
66 // In LLVM 3.7.x and earlier, we use createBasicAliasAnalysisPass
67 // from llvm/Analysis/Passes.h (already included above)
68 
69 #if defined (HAVE_LLVM_BITCODE_READERWRITER_H)
70 // In LLVM <= 3.9, only one header for bitcode read/writer
71 # include <llvm/Bitcode/ReaderWriter.h>
72 #else
73 // Starting with LLVM 4.0, two separate headers
74 # include <llvm/Bitcode/BitcodeReader.h>
75 # include <llvm/Bitcode/BitcodeWriter.h>
76 #endif
77 
78 #include <llvm/ExecutionEngine/ExecutionEngine.h>
79 // old JIT, LLVM < 3.6.0
80 // #include <llvm/ExecutionEngine/JIT.h>
81 // MCJIT, LLVM >= 3.0.0
82 #include <llvm/ExecutionEngine/MCJIT.h>
83 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
84 
85 #if defined (LEGACY_PASSMANAGER)
86 # include <llvm/IR/LegacyPassManager.h>
87 #else
88 # include <llvm/PassManager.h>
89 #endif
90 
91 #if defined (HAVE_LLVM_IR_FUNCTION_H)
92 # include <llvm/IR/LLVMContext.h>
93 # include <llvm/IR/Module.h>
94 # include <llvm/IR/Intrinsics.h>
95 #else
96 # include <llvm/LLVMContext.h>
97 # include <llvm/Module.h>
98 # include <llvm/Intrinsics.h>
99 #endif
100 
101 #if defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
102 # include <llvm/Support/IRBuilder.h>
103 #elif defined(HAVE_LLVM_IR_IRBUILDER_H)
104 # include <llvm/IR/IRBuilder.h>
105 #else
106 # include <llvm/IRBuilder.h>
107 #endif
108 
109 #include <llvm/Support/raw_os_ostream.h>
110 #include <llvm/Support/TargetSelect.h>
111 
112 #if defined (HAVE_LLVM_IR_DATALAYOUT_H)
113 # include <llvm/IR/DataLayout.h>
114 #elif defined(HAVE_LLVM_DATALAYOUT_H)
115 # include <llvm/DataLayout.h>
116 #else
117 # include <llvm/Target/TargetData.h>
118 #endif
119 
120 #include <llvm/Transforms/IPO.h>
121 #include <llvm/Transforms/Scalar.h>
122 
123 // Starting with LLVM 3.9.0, llvm::createGVNPass has
124 // been moved to a new header file named GVN.h
125 // (before that it was in llvm/Transforms/Scalar.h)
126 #if defined (HAVE_LLVM_TRANSFORMS_SCALAR_GVN_H)
127 # include <llvm/Transforms/Scalar/GVN.h>
128 #endif
129 
130 static bool Vdebug_jit = false;
131 
132 static bool Vjit_enable = false;
133 
134 static int Vjit_startcnt = 1000;
135 
136 static int Vjit_failcnt = 0;
137 
138 namespace octave
139 {
140  namespace jit
141  {
142 #if defined (LEGACY_PASSMANAGER)
145 #else
148 #endif
149  }
150 
152 
153  static llvm::LLVMContext& context = tree_jit::llvm_context;
154 
155  // -------------------- jit_break_exception --------------------
156 
157  // jit_break is thrown whenever a branch we are converting has only breaks or
158  // continues. This is because all code that follows a break or continue
159  // is dead.
160  class jit_break_exception : public std::exception
161  { };
162 
163  // -------------------- jit_convert --------------------
165  : m_converting_function (false)
166  {
167  initialize (__get_current_scope__ ("jit_convert::jit_convert"));
168 
169  if (for_bounds)
170  create_variable (next_for_bounds (false), for_bounds);
171 
172  try
173  {
174  visit (tee);
175  }
176  catch (const jit_break_exception&)
177  { }
178 
179  // breaks must have been handled by the top level loop
180  assert (m_breaks.empty ());
181  assert (m_continues.empty ());
182 
185 
186  for (auto iter = m_vmap.begin (); iter != m_vmap.end (); ++iter)
187  {
188  jit_variable *var = iter->second;
189  const std::string& name = var->name ();
190  if (name.size () && name[0] != '#')
192  }
193 
195  }
196 
198  const std::vector<jit_type *>& args)
199  : m_converting_function (true)
200  {
201  initialize (fcn.scope ());
202 
203  tree_parameter_list *plist = fcn.parameter_list ();
204  tree_parameter_list *rlist = fcn.return_list ();
205  if (plist && plist->takes_varargs ())
206  throw jit_fail_exception ("varags not supported");
207 
208  if (rlist && (rlist->size () > 1 || rlist->takes_varargs ()))
209  throw jit_fail_exception ("multiple returns not supported");
210 
211  if (plist)
212  {
213  auto piter = plist->begin ();
214  for (size_t i = 0; i < args.size (); ++i, ++piter)
215  {
216  if (piter == plist->end ())
217  throw jit_fail_exception ("Too many parameter to function");
218 
219  tree_decl_elt *elt = *piter;
220  std::string name = elt->name ();
221  create_variable (name, args[i]);
222  }
223  }
224 
225  jit_value *return_value = nullptr;
226  bool all_breaking = false;
227  if (fcn.is_special_expr ())
228  {
229  tree_expression *expr = fcn.special_expr ();
230  if (expr)
231  {
232  jit_variable *retvar = get_variable ("#return");
233  jit_value *retval = nullptr;
234  try
235  {
236  retval = visit (expr);
237  }
238  catch (const jit_break_exception&)
239  { }
240 
241  if (m_breaks.size () || m_continues.size ())
242  throw jit_fail_exception ("break/continue not supported in "
243  "anonymous functions");
244 
246  return_value = retvar;
247  }
248  }
249  else
250  {
251  try
252  {
253  visit_statement_list (*fcn.body ());
254  }
255  catch (const jit_break_exception&)
256  {
257  all_breaking = true;
258  }
259 
260  // the user may use break or continue to exit the function
263  }
264 
265  if (! all_breaking)
267 
270 
271  if (! return_value && rlist && rlist->size () == 1)
272  {
273  tree_decl_elt *elt = rlist->front ();
274  return_value = get_variable (elt->name ());
275  }
276 
277  // FIXME: We should use live range analysis to delete variables where
278  // needed. For now we just delete everything at the end of the function.
279  for (auto iter = m_vmap.begin ();
280  iter != m_vmap.end ();
281  ++iter)
282  {
283  if (iter->second != return_value)
284  {
285  jit_call *call;
287  iter->second);
288  m_final_block->append (call);
289  }
290  }
291 
292  if (return_value)
293  m_final_block->append (m_factory.create<jit_return> (return_value));
294  else
296  }
297 
298  void
300  {
301  throw jit_fail_exception ("No visit_anon_fcn_handle implementation");
302  }
303 
304  void
306  {
307  throw jit_fail_exception ("No visit_argument_list implementation");
308  }
309 
310  void
312  {
313  tree_expression *lhs = be.lhs ();
314  jit_value *lhsv = visit (lhs);
315 
316  tree_expression *rhs = be.rhs ();
317  jit_value *rhsv = visit (rhs);
318 
319  const jit_operation& fn = jit_typeinfo::binary_op (be.op_type ());
320  m_result = create_checked (fn, lhsv, rhsv);
321  }
322 
323  void
325  {
326  bool is_and = be.op_type () == tree_boolean_expression::bool_and;
327 
328  std::string short_name = next_shortcircut_result ();
329  jit_variable *short_result = m_factory.create<jit_variable> (short_name);
330  m_vmap[short_name] = short_result;
331 
333  tree_expression *lhs = be.lhs ();
334  jit_value *lhsv = visit (lhs);
336 
337  jit_block *short_early = m_factory.create<jit_block> ("short_early");
338  m_blocks.push_back (short_early);
339 
340  jit_block *short_cont = m_factory.create<jit_block> ("short_cont");
341 
342  if (is_and)
343  m_block->append (m_factory.create<jit_cond_branch> (lhsv, short_cont,
344  short_early));
345  else
346  m_block->append (m_factory.create<jit_cond_branch> (lhsv, short_early,
347  short_cont));
348 
349  m_block = short_early;
350 
351  jit_value *early_result = m_factory.create<jit_const_bool> (! is_and);
352  m_block->append (m_factory.create<jit_assign> (short_result, early_result));
354 
355  m_blocks.push_back (short_cont);
356  m_block = short_cont;
357 
358  tree_expression *rhs = be.rhs ();
359  jit_value *rhsv = visit (rhs);
361  m_block->append (m_factory.create<jit_assign> (short_result, rhsv));
363 
364  m_blocks.push_back (done);
365  m_block = done;
366  m_result = short_result;
367  }
368 
369  void
371  {
372  m_breaks.push_back (m_block);
373  throw jit_break_exception ();
374  }
375 
376  void
378  {
379  // in the further we need to add support for classes and deal with rvalues
380  jit_value *base = visit (expr.base ());
381  jit_value *limit = visit (expr.limit ());
382  jit_value *increment;
383  tree_expression *tinc = expr.increment ();
384 
385  if (tinc)
386  increment = visit (tinc);
387  else
388  increment = m_factory.create<jit_const_scalar> (1);
389 
391  base, limit, increment));
392  }
393 
394  void
396  {
397  m_continues.push_back (m_block);
398  throw jit_break_exception ();
399  }
400 
401  void
403  {
404  throw jit_fail_exception ("No visit_decl_command implementation");
405  }
406 
407  void
409  {
410  throw jit_fail_exception ("No visit_decl_elt implementation");
411  }
412 
413  void
415  {
416  throw jit_fail_exception ("No visit_decl_init_list implementation");
417  }
418 
419  void
421  {
422  // Note we do an initial check to see if the loop will run at least once.
423  // This allows us to get better type inference bounds on variables defined
424  // and used only inside the for loop (e.g., the index variable)
425 
426  // If we are a nested for loop we need to store the previous breaks
427  unwind_protect frame;
428  frame.protect_var (m_breaks);
429  frame.protect_var (m_continues);
430  m_breaks.clear ();
431  m_continues.clear ();
432 
433  // Need a variable for our iterator, because it is used in multiple blocks
434  std::string iter_name = next_iterator ();
435  jit_variable *iterator = m_factory.create<jit_variable> (iter_name);
436  m_factory.create<jit_variable> (iter_name);
437  m_vmap[iter_name] = iterator;
438 
439  jit_block *body = m_factory.create<jit_block> ("for_body");
440  jit_block *tail = m_factory.create<jit_block> ("for_tail");
441 
442  // Do control expression, iter init, and condition check in prev_block
443  // (block).
444  // if we are the top level for loop, the bounds is an input argument.
445  jit_value *control = find_variable (next_for_bounds ());
446  if (! control)
447  control = visit (cmd.control_expr ());
449  control);
450  m_block->append (init_iter);
451  m_block->append (m_factory.create<jit_assign> (iterator, init_iter));
452 
454  control, iterator);
455  m_block->append (check);
456  m_block->append (m_factory.create<jit_cond_branch> (check, body, tail));
457 
458  m_blocks.push_back (body);
459  m_block = body;
460 
461  // compute the syntactical iterator
463  control, iterator);
464  m_block->append (idx_rhs);
465  do_assign (cmd.left_hand_side (), idx_rhs);
466 
467  // do loop
468  tree_statement_list *pt_body = cmd.body ();
469  bool all_breaking = false;
470  try
471  {
472  pt_body->accept (*this);
473  }
474  catch (const jit_break_exception&)
475  {
476  if (m_continues.empty ())
477  {
478  // WTF are you doing user? Every branch was a break, why did you
479  // have a loop??? Users are silly people...
482  m_block = tail;
483  return;
484  }
485 
486  all_breaking = true;
487  }
488 
489  // check our condition, continues jump to this block
490  jit_block *check_block = m_factory.create<jit_block> ("for_check");
491  m_blocks.push_back (check_block);
492 
493  jit_block *interrupt_check = m_factory.create<jit_block> ("for_interrupt");
494  m_blocks.push_back (interrupt_check);
495 
496  if (! all_breaking)
497  m_block->append (m_factory.create<jit_branch> (check_block));
498  finish_breaks (check_block, m_continues);
499 
500  m_block = check_block;
503  jit_call *iter_inc = m_factory.create<jit_call> (add_fn, iterator, one);
504  m_block->append (iter_inc);
505  m_block->append (m_factory.create<jit_assign> (iterator, iter_inc));
507  control, iterator));
508  m_block->append (m_factory.create<jit_cond_branch> (check, interrupt_check,
509  tail));
510 
511  m_block = interrupt_check;
512  jit_error_check *ec
514  body, m_final_block);
515  m_block->append (ec);
516 
517  // breaks will go to our tail
520  m_block = tail;
521  }
522 
523  void
525  {
526  throw jit_fail_exception ("No visit_complex_for_command implementation");
527  }
528 
529  void
531  {
532  throw jit_fail_exception ("No visit_octave_user_script implementation");
533  }
534 
535  void
537  {
538  throw jit_fail_exception ("No visit_octave_user_function implementation");
539  }
540 
541  void
543  {
544  throw jit_fail_exception ("No visit_octave_user_function_header implementation");
545  }
546 
547  void
549  {
550  throw jit_fail_exception ("No visit_octave_user_function_trailer implementation");
551  }
552 
553  void
555  {
556  throw jit_fail_exception ("No visit_function_def implementation");
557  }
558 
559  void
561  {
562  if (ti.has_magic_end ())
563  {
564  if (! m_end_context.size ())
565  throw jit_fail_exception ("Illegal end");
567  }
568  else
569  {
570  jit_variable *var = get_variable (ti.name ());
571  jit_instruction *instr;
572  instr = m_factory.create<jit_call> (&jit_typeinfo::grab, var);
573  m_result = m_block->append (instr);
574  }
575  }
576 
577  void
579  {
580  throw jit_fail_exception ("No visit_if_clause implementation");
581  }
582 
583  void
585  {
586  tree_if_clause *last = lst.back ();
587  size_t last_else = static_cast<size_t> (last->is_else_clause ());
588 
589  // entry_blocks represents the block you need to enter in order to execute
590  // the condition check for the ith clause. For the else, it is simple the
591  // else body. If there is no else body, then it is padded with the tail.
592  std::vector<jit_block *> entry_blocks (lst.size () + 1 - last_else);
593  entry_blocks[0] = m_block;
594 
595  // Need to construct blocks first, because they have jumps to each other.
596  auto iter = lst.begin ();
597  ++iter;
598  for (size_t i = 1; iter != lst.end (); ++iter, ++i)
599  {
600  tree_if_clause *tic = *iter;
601  if (tic->is_else_clause ())
602  entry_blocks[i] = m_factory.create<jit_block> ("else");
603  else
604  entry_blocks[i] = m_factory.create<jit_block> ("ifelse_cond");
605  }
606 
607  jit_block *tail = m_factory.create<jit_block> ("if_tail");
608  if (! last_else)
609  entry_blocks[entry_blocks.size () - 1] = tail;
610 
611  // each branch in the if statement will have different breaks/continues
612  block_list current_breaks = m_breaks;
613  block_list current_continues = m_continues;
614  m_breaks.clear ();
615  m_continues.clear ();
616 
617  size_t num_incoming = 0; // number of incoming blocks to our tail
618  iter = lst.begin ();
619  for (size_t i = 0; iter != lst.end (); ++iter, ++i)
620  {
621  tree_if_clause *tic = *iter;
622  m_block = entry_blocks[i];
623  assert (m_block);
624 
625  if (i) // the first block is prev_block, so it has already been added
626  m_blocks.push_back (entry_blocks[i]);
627 
628  if (! tic->is_else_clause ())
629  {
630  tree_expression *expr = tic->condition ();
631  jit_value *cond = visit (expr);
633  cond);
634  jit_block *body = m_factory.create<jit_block> (i == 0 ? "if_body"
635  : "ifelse_body");
636  m_blocks.push_back (body);
637 
639  body,
640  entry_blocks[i + 1]);
641  m_block->append (br);
642  m_block = body;
643  }
644 
645  tree_statement_list *stmt_lst = tic->commands ();
646  assert (stmt_lst); // jwe: Can this be null?
647 
648  try
649  {
650  stmt_lst->accept (*this);
651  ++num_incoming;
653  }
654  catch (const jit_break_exception&)
655  { }
656 
657  current_breaks.splice (current_breaks.end (), m_breaks);
658  current_continues.splice (current_continues.end (), m_continues);
659  }
660 
661  m_breaks.splice (m_breaks.end (), current_breaks);
662  m_continues.splice (m_continues.end (), current_continues);
663 
664  if (num_incoming || ! last_else)
665  {
667  m_block = tail;
668  }
669  else
670  // every branch broke, so we don't have a tail
671  throw jit_break_exception ();
672  }
673 
674  void
676  {
677  m_result = resolve (exp);
678  }
679 
680  void
682  {
683  throw jit_fail_exception ("No visit_matrix implementation");
684  }
685 
686  void
688  {
689  throw jit_fail_exception ("No visit_cell implementation");
690  }
691 
692  void
694  {
695  throw jit_fail_exception ("No visit_multi_assignment implementation");
696  }
697 
698  void
700  {
701  throw jit_fail_exception ("No visit_no_op_command implementation");
702  }
703 
704  void
706  {
707  octave_value v = tc.value ();
708 
710 
711  if (ty == jit_typeinfo::get_scalar ())
712  {
713  double dv = v.double_value ();
715  }
716  else if (ty == jit_typeinfo::get_range ())
717  {
718  Range rv = v.range_value ();
720  }
721  else if (ty == jit_typeinfo::get_complex ())
722  {
723  Complex cv = v.complex_value ();
725  }
726  else
727  throw jit_fail_exception ("Unknown constant");
728  }
729 
730  void
732  {
733  throw jit_fail_exception ("No visit_fcn_handle implementation");
734  }
735 
736  void
738  {
739  throw jit_fail_exception ("No visit_parameter_list implementation");
740  }
741 
742  void
744  {
745  octave_value::unary_op etype = tpe.op_type ();
746  tree_expression *operand = tpe.operand ();
747  jit_value *operandv = visit (operand);
748 
749  const jit_operation& fn = jit_typeinfo::unary_op (etype);
750  m_result = create_checked (fn, operandv);
751 
752  if (etype == octave_value::op_incr || etype == octave_value::op_decr)
753  {
754  jit_value *ret = create_checked (&jit_typeinfo::grab, operandv);
755  do_assign (operand, m_result);
756  m_result = ret;
757  }
758  }
759 
760  void
762  {
763  octave_value::unary_op etype = tpe.op_type ();
764  tree_expression *operand = tpe.operand ();
765  const jit_operation& fn = jit_typeinfo::unary_op (etype);
766  m_result = create_checked (fn, visit (operand));
767 
768  if (etype == octave_value::op_incr || etype == octave_value::op_decr)
769  do_assign (operand, m_result);
770  }
771 
772  void
774  {
775  throw jit_fail_exception ("No visit_return_command implementation");
776  }
777 
778  void
780  {
781  tree_expression *rhs = tsa.right_hand_side ();
782  jit_value *rhsv = visit (rhs);
783  octave_value::assign_op op = tsa.op_type ();
784 
785  if (op != octave_value::op_asn_eq)
786  {
787  // Do the equivalent binary operation, then assign.
788  // This is always correct, but it isn't always optimal.
789  tree_expression *lhs = tsa.left_hand_side ();
790  jit_value *lhsv = visit (lhs);
792  const jit_operation& fn = jit_typeinfo::binary_op (bop);
793  rhsv = create_checked (fn, lhsv, rhsv);
794  }
795 
796  m_result = do_assign (tsa.left_hand_side (), rhsv);
797  }
798 
799  void
801  {
802  tree_command *cmd = stmt.command ();
803  tree_expression *expr = stmt.expression ();
804 
805  if (cmd)
806  visit (cmd);
807  else
808  {
809  // stolen from tree_evaluator::visit_statement
810  bool do_bind_ans = false;
811 
812  if (expr->is_identifier ())
813  {
814  tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
815 
816  do_bind_ans = (! id->is_variable (m_scope.current_context ()));
817  }
818  else
819  do_bind_ans = (! expr->is_assignment_expression ());
820 
821  jit_value *expr_result = visit (expr);
822 
823  if (do_bind_ans)
824  do_assign ("ans", expr_result, expr->print_result ());
825  else if (expr->is_identifier () && expr->print_result ())
826  {
827  // FIXME: ugly hack, we need to come up with a way to pass
828  // nargout to visit_identifier
831  (expr->name ());
833  expr_result));
834  }
835  }
836  }
837 
838  void
840  {
841  throw jit_fail_exception ("No visit_switch_case implementation");
842  }
843 
844  void
846  {
847  throw jit_fail_exception ("No visit_switch_case_list implementation");
848  }
849 
850  void
852  {
853  tree_switch_case_list *lst = cmd.case_list ();
854 
855  // always visit switch expression
856  tree_expression *expr = cmd.switch_value ();
857  assert (expr && "Switch value can not be null");
858  jit_value *value = visit (expr);
859  assert (value);
860 
861  size_t case_blocks_num = lst->size ();
862 
863  if (! case_blocks_num) // there's nothing to do
864  return;
865 
866  // check for otherwise, it's interpreted as last 'else' condition
867  size_t has_otherwise = 0;
868  tree_switch_case *last = lst->back ();
869  if (last->is_default_case ())
870  has_otherwise = 1;
871 
872  std::vector<jit_block *> entry_blocks (case_blocks_num+1 - has_otherwise);
873 
874  // the first entry point is always the actual block. Afterward, new blocks
875  // are created for every case and the otherwise branch
876  entry_blocks[0] = m_block;
877  for (size_t i = 1; i < case_blocks_num; ++i)
878  entry_blocks[i] = m_factory.create<jit_block> ("case_cond");
879 
880  jit_block *tail = m_factory.create<jit_block> ("switch_tail");
881 
882  // if there's no otherwise branch, the 'else' of the last branch
883  // has to point to the tail
884  if (! has_otherwise)
885  entry_blocks[entry_blocks.size()-1] = tail;
886 
887  // each branch in the case statement will have different breaks/continues
888  block_list current_breaks = m_breaks;
889  block_list current_continues = m_continues;
890  m_breaks.clear ();
891  m_continues.clear ();
892 
893  size_t num_incoming = 0; // number of incoming blocks to our tail
894 
895  auto iter = lst->begin ();
896  for (size_t i = 0; i < case_blocks_num; ++iter, ++i)
897  {
898  tree_switch_case *twc = *iter;
899  m_block = entry_blocks[i]; // case_cond
900  assert (m_block);
901 
902  if (i)
903  m_blocks.push_back (entry_blocks[i]); // first block already pushed
904 
905  if (! twc->is_default_case ())
906  {
907  // compare result of switch expression with actual case label
908  tree_expression *te = twc->case_label ();
909  jit_value *label = visit (te);
910  assert(label);
911 
913  jit_value *cond = create_checked (fn, value, label);
914  assert(cond);
915 
917  cond);
918 
919  jit_block *body = m_factory.create<jit_block> ("case_body");
920  m_blocks.push_back (body);
921 
923  entry_blocks[i+1]));
924  m_block = body; // case_body
925  }
926 
927  tree_statement_list *stmt_lst = twc->commands ();
928  assert(stmt_lst);
929 
930  try
931  {
932  stmt_lst->accept (*this);
933  num_incoming++;
935  }
936  catch (const jit_break_exception&)
937  { }
938 
939  // each branch in the case statement will have different
940  // breaks/continues
941  current_breaks.splice (current_breaks.end (), m_breaks);
942  current_continues.splice (current_continues.end (), m_continues);
943  }
944 
945  // each branch in the case statement will have different breaks/continues
946  m_breaks.splice (m_breaks.end (), current_breaks);
947  m_continues.splice (m_continues.end (), current_continues);
948 
949  if (num_incoming || ! has_otherwise)
950  {
952  m_block = tail; // switch_tail
953  }
954  else
955  throw jit_break_exception (); // every branch broke
956  }
957 
958  void
960  {
961  throw jit_fail_exception ("No visit_try_catch_command implementation");
962  }
963 
964  void
966  {
967  throw jit_fail_exception ("No visit_unwind_protect_command implementation");
968  }
969 
970  void
972  {
973  unwind_protect frame;
974  frame.protect_var (m_breaks);
975  frame.protect_var (m_continues);
976  m_breaks.clear ();
977  m_continues.clear ();
978 
979  jit_block *cond_check = m_factory.create<jit_block> ("while_cond_check");
980  m_block->append (m_factory.create<jit_branch> (cond_check));
981  m_blocks.push_back (cond_check);
982  m_block = cond_check;
983 
984  tree_expression *expr = wc.condition ();
985  assert (expr && "While expression can not be null");
986  jit_value *check = visit (expr);
988 
989  jit_block *body = m_factory.create<jit_block> ("while_body");
990  m_blocks.push_back (body);
991 
992  jit_block *tail = m_factory.create<jit_block> ("while_tail");
993  m_block->append (m_factory.create<jit_cond_branch> (check, body, tail));
994  m_block = body;
995 
996  tree_statement_list *loop_body = wc.body ();
997  bool all_breaking = false;
998  if (loop_body)
999  {
1000  try
1001  {
1002  loop_body->accept (*this);
1003  }
1004  catch (const jit_break_exception&)
1005  {
1006  all_breaking = true;
1007  }
1008  }
1009 
1011 
1012  if (! all_breaking || m_continues.size ())
1013  {
1014  jit_block *interrupt_check
1015  = m_factory.create<jit_block> ("interrupt_check");
1016  m_blocks.push_back (interrupt_check);
1017  finish_breaks (interrupt_check, m_continues);
1018  if (! all_breaking)
1019  m_block->append (m_factory.create<jit_branch> (interrupt_check));
1020 
1021  m_block = interrupt_check;
1022  jit_error_check *ec
1024  cond_check, m_final_block);
1025  m_block->append (ec);
1026  }
1027 
1029  m_block = tail;
1030  }
1031 
1032  void
1034  {
1035  unwind_protect frame;
1036  frame.protect_var (m_breaks);
1037  frame.protect_var (m_continues);
1038  m_breaks.clear ();
1039  m_continues.clear ();
1040 
1041  jit_block *body = m_factory.create<jit_block> ("do_until_body");
1042  jit_block *cond_check = m_factory.create<jit_block> ("do_until_cond_check");
1043  jit_block *tail = m_factory.create<jit_block> ("do_until_tail");
1044 
1046  m_blocks.push_back (body);
1047  m_block = body;
1048 
1049  tree_statement_list *loop_body = duc.body ();
1050  bool all_breaking = false;
1051  if (loop_body)
1052  {
1053  try
1054  {
1055  loop_body->accept (*this);
1056  }
1057  catch (const jit_break_exception&)
1058  {
1059  all_breaking = true;
1060  }
1061  }
1062 
1064 
1065  if (! all_breaking || m_continues.size ())
1066  {
1067  jit_block *interrupt_check
1068  = m_factory.create<jit_block> ("interrupt_check");
1069  m_blocks.push_back (interrupt_check);
1070  finish_breaks (interrupt_check, m_continues);
1071  if (! all_breaking)
1072  m_block->append (m_factory.create<jit_branch> (interrupt_check));
1073 
1074  m_block = interrupt_check;
1075  jit_error_check *ec
1077  cond_check, m_final_block);
1078  m_block->append (ec);
1079 
1080  m_blocks.push_back (cond_check);
1081  m_block = cond_check;
1082 
1083  tree_expression *expr = duc.condition ();
1084  assert (expr && "Do-Until expression can not be null");
1085  jit_value *check = visit (expr);
1086  check = create_checked (&jit_typeinfo::logically_true, check);
1087 
1089  body));
1090  }
1091 
1093  m_block = tail;
1094  }
1095 
1096  void
1098  {
1099  m_scope = s;
1100  m_iterator_count = 0;
1101  m_for_bounds_count = 0;
1102  m_short_count = 0;
1104 
1106  m_final_block = m_factory.create<jit_block> ("final");
1110  }
1111 
1112  jit_call *
1114  {
1115  m_block->append (ret);
1116 
1117  jit_block *normal = m_factory.create<jit_block> (m_block->name ());
1118  jit_error_check *check
1120  ret, normal, m_final_block);
1121  m_block->append (check);
1122  m_blocks.push_back (normal);
1123  m_block = normal;
1124 
1125  return ret;
1126  }
1127 
1128  jit_variable *
1129  jit_convert::find_variable (const std::string& vname) const
1130  {
1131  variable_map::const_iterator iter;
1132  iter = m_vmap.find (vname);
1133  return iter != m_vmap.end () ? iter->second : nullptr;
1134  }
1135 
1136  jit_variable *
1137  jit_convert::get_variable (const std::string& vname)
1138  {
1139  jit_variable *ret = find_variable (vname);
1140  if (ret)
1141  return ret;
1142 
1143  symbol_table& symtab = __get_symbol_table__ ("jit_convert::find_variable");
1144 
1145  symbol_record record = m_scope.find_symbol (vname);
1146  if (record.is_persistent () || record.is_global ())
1147  throw jit_fail_exception ("Persistent and global not yet supported");
1148 
1150  return create_variable (vname, jit_typeinfo::get_any (), false);
1151  else
1152  {
1153  octave_value val = record.varval (m_scope.current_context ());
1154  if (val.is_undefined ())
1155  val = symtab.find_function (vname);
1156 
1158  m_bounds.push_back (type_bound (type, vname));
1159 
1160  return create_variable (vname, type);
1161  }
1162  }
1163 
1164  jit_variable *
1165  jit_convert::create_variable (const std::string& vname, jit_type *type,
1166  bool isarg)
1167  {
1168  jit_variable *var = m_factory.create<jit_variable> (vname);
1169 
1170  if (isarg)
1171  {
1172  jit_extract_argument *extract;
1173  extract = m_factory.create<jit_extract_argument> (type, var);
1174  m_entry_block->prepend (extract);
1175  }
1176  else
1177  {
1179  jit_assign *assign = m_factory.create<jit_assign> (var, init);
1180  m_entry_block->prepend (assign);
1181  m_entry_block->prepend (init);
1182  }
1183 
1184  return m_vmap[vname] = var;
1185  }
1186 
1187  std::string
1188  jit_convert::next_name (const char *prefix, size_t& count, bool inc)
1189  {
1190  std::stringstream ss;
1191  ss << prefix << count;
1192  if (inc)
1193  ++count;
1194  return ss.str ();
1195  }
1196 
1197  jit_instruction *
1199  bool lhs)
1200  {
1201  std::string type = exp.type_tags ();
1202  if (! (type.size () == 1 && type[0] == '('))
1203  throw jit_fail_exception ("Unsupported index operation");
1204 
1205  std::list<tree_argument_list *> args = exp.arg_lists ();
1206  if (args.size () != 1)
1207  throw jit_fail_exception ("Bad number of arguments in "
1208  "tree_index_expression");
1209 
1210  tree_argument_list *arg_list = args.front ();
1211  if (! arg_list)
1212  throw jit_fail_exception ("null argument list");
1213 
1214  if (arg_list->size () < 1)
1215  throw jit_fail_exception ("Empty arg_list");
1216 
1217  tree_expression *tree_object = exp.expression ();
1218  jit_value *object;
1219  if (lhs)
1220  {
1221  tree_identifier *id = dynamic_cast<tree_identifier *> (tree_object);
1222  if (! id)
1223  throw jit_fail_exception ("expected identifier");
1224  object = get_variable (id->name ());
1225  }
1226  else
1227  object = visit (tree_object);
1228 
1229  size_t narg = arg_list->size ();
1230  auto iter = arg_list->begin ();
1231  bool have_extra = extra_arg;
1232  std::vector<jit_value *> call_args (narg + 1 + have_extra);
1233  call_args[0] = object;
1234 
1235  for (size_t idx = 0; iter != arg_list->end (); ++idx, ++iter)
1236  {
1237  unwind_protect frame;
1238  frame.add_method (&m_end_context,
1239  &std::vector<jit_magic_end::context>::pop_back);
1240 
1241  jit_magic_end::context ctx (m_factory, object, idx, narg);
1242  m_end_context.push_back (ctx);
1243  call_args[idx + 1] = visit (*iter);
1244  }
1245 
1246  if (extra_arg)
1247  call_args[call_args.size () - 1] = extra_arg;
1248 
1249  const jit_operation& fres = (lhs ? jit_typeinfo::paren_subsasgn ()
1251 
1252  return create_checked (fres, call_args);
1253  }
1254 
1255  jit_value *
1257  artificial)
1258  {
1259  if (! exp)
1260  throw jit_fail_exception ("NULL lhs in assign");
1261 
1262  if (isa<tree_identifier> (exp))
1263  return do_assign (exp->name (), rhs, exp->print_result (), artificial);
1264  else if (tree_index_expression *idx
1265  = dynamic_cast<tree_index_expression *> (exp))
1266  {
1267  jit_value *new_object = resolve (*idx, rhs, true);
1268  do_assign (idx->expression (), new_object, true);
1269 
1270  // FIXME: Will not work for values that must be released/grabbed
1271  return rhs;
1272  }
1273  else
1274  throw jit_fail_exception ("Unsupported assignment");
1275  }
1276 
1277  jit_value *
1278  jit_convert::do_assign (const std::string& lhs, jit_value *rhs,
1279  bool print, bool artificial)
1280  {
1281  jit_variable *var = get_variable (lhs);
1282  jit_assign *assign = m_block->append (m_factory.create<jit_assign> (var,
1283  rhs));
1284 
1285  if (artificial)
1286  assign->mark_artificial ();
1287 
1288  if (print)
1289  {
1290  const jit_operation& print_fn = jit_typeinfo::print_value ();
1292  m_block->append (m_factory.create<jit_call> (print_fn, name, var));
1293  }
1294 
1295  return var;
1296  }
1297 
1298  jit_value *
1300  {
1301  unwind_protect frame;
1302  frame.protect_var (m_result);
1303 
1304  tee.accept (*this);
1305  return m_result;
1306  }
1307 
1308  void
1310  {
1311  for (auto iter = lst.begin (); iter != lst.end (); ++iter)
1312  {
1313  jit_block *b = *iter;
1314  b->append (m_factory.create<jit_branch> (dest));
1315  }
1316  }
1317 
1318  // -------------------- jit_convert_llvm --------------------
1319  llvm::Function *
1321  const jit_block_list& blocks,
1322  const std::list<jit_value *>& constants,
1323  const std::string& llvm_function_name)
1324  {
1325  m_converting_function = false;
1326 
1327  // for now just init arguments from entry, later we will have to do
1328  // something more interesting
1329  jit_block *m_entry_block = blocks.front ();
1330  for (auto iter = m_entry_block->begin ();
1331  iter != m_entry_block->end (); ++iter)
1332  if (jit_extract_argument *extract
1333  = dynamic_cast<jit_extract_argument *> (*iter))
1334  m_argument_vec.push_back (std::make_pair (extract->name (), true));
1335 
1336  jit_type *any = jit_typeinfo::get_any ();
1337 
1338  // argument is an array of octave_base_value*, or octave_base_value**
1339  llvm::Type *arg_type = any->to_llvm (); // this is octave_base_value*
1340  llvm::FunctionType *ft;
1341  ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context),
1342  arg_type->getPointerTo (), false);
1343 
1344  m_function = module.create_llvm_function (ft, llvm_function_name);
1345  try
1346  {
1347  m_prelude = llvm::BasicBlock::Create (context, "prelude", m_function);
1348  builder.SetInsertPoint (m_prelude);
1349 
1350  // The jitted function will have only one function argument, of
1351  // octave_base_value** type
1352  llvm::Value *arg = &*(m_function->arg_begin ());
1353 
1354  for (size_t i = 0; i < m_argument_vec.size (); ++i)
1355  {
1356 #if defined (LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_REQUIRES_TYPE)
1357  // LLVM >= 3.7
1358  llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg_type, arg, i);
1359 #else
1360  // LLVM <= 3.6
1361  llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg, i);
1362 #endif
1363  m_arguments[m_argument_vec[i].first] = loaded_arg;
1364  }
1365 
1366  convert (blocks, constants);
1367  }
1368  catch (const jit_fail_exception& e)
1369  {
1370  m_function->eraseFromParent ();
1371  throw;
1372  }
1373 
1374  return m_function;
1375  }
1376 
1377  jit_function
1379  const jit_block_list& blocks,
1380  const std::list<jit_value *>& constants,
1381  octave_user_function& fcn,
1382  const std::vector<jit_type *>& args)
1383  {
1384  m_converting_function = true;
1385 
1386  jit_block *m_final_block = blocks.back ();
1387  jit_return *ret = dynamic_cast<jit_return *> (m_final_block->back ());
1388  assert (ret);
1389 
1391  "foobar", ret->result_type (), args);
1393 
1394  try
1395  {
1396  m_prelude = m_creating.new_block ("prelude");
1397  builder.SetInsertPoint (m_prelude);
1398 
1399  tree_parameter_list *plist = fcn.parameter_list ();
1400  if (plist)
1401  {
1402  auto piter = plist->begin ();
1403  auto pend = plist->end ();
1404  for (size_t i = 0; i < args.size () && piter != pend; ++i, ++piter)
1405  {
1406  tree_decl_elt *elt = *piter;
1407  std::string arg_name = elt->name ();
1408  m_arguments[arg_name] = m_creating.argument (builder, i);
1409  }
1410  }
1411 
1412  convert (blocks, constants);
1413  }
1414  catch (const jit_fail_exception& e)
1415  {
1416  m_function->eraseFromParent ();
1417  throw;
1418  }
1419 
1420  return m_creating;
1421  }
1422 
1423  void
1425  const std::list<jit_value *>& constants)
1426  {
1427  std::list<jit_block *>::const_iterator biter;
1428  for (biter = blocks.begin (); biter != blocks.end (); ++biter)
1429  {
1430  jit_block *jblock = *biter;
1431  llvm::BasicBlock *m_block = llvm::BasicBlock::Create (context,
1432  jblock->name (),
1433  m_function);
1434  jblock->stash_llvm (m_block);
1435  }
1436 
1437  jit_block *first = *blocks.begin ();
1438  builder.CreateBr (first->to_llvm ());
1439 
1440  // constants aren't in the IR, we visit those first
1441  for (auto iter = constants.begin (); iter != constants.end (); ++iter)
1442  if (! isa<jit_instruction> (*iter))
1443  visit (*iter);
1444 
1445  // convert all instructions
1446  for (biter = blocks.begin (); biter != blocks.end (); ++biter)
1447  visit (*biter);
1448 
1449  // now finish phi nodes
1450  for (biter = blocks.begin (); biter != blocks.end (); ++biter)
1451  {
1452  jit_block& m_block = **biter;
1453  for (auto piter = m_block.begin ();
1454  piter != m_block.end () && isa<jit_phi> (*piter); ++piter)
1455  {
1456  jit_instruction *phi = *piter;
1457  finish_phi (static_cast<jit_phi *> (phi));
1458  }
1459  }
1460  }
1461 
1462  void
1464  {
1465  llvm::PHINode *llvm_phi = phi->to_llvm ();
1466  for (size_t i = 0; i < phi->argument_count (); ++i)
1467  {
1468  llvm::BasicBlock *pred = phi->incoming_llvm (i);
1469  llvm_phi->addIncoming (phi->argument_llvm (i), pred);
1470  }
1471  }
1472 
1473  void
1475  {
1476  cs.stash_llvm (builder.CreateGlobalStringPtr (cs.value ()));
1477  }
1478 
1479  void
1481  {
1482  cb.stash_llvm (llvm::ConstantInt::get (cb.type_llvm (), cb.value ()));
1483  }
1484 
1485  void
1487  {
1488  cs.stash_llvm (llvm::ConstantFP::get (cs.type_llvm (), cs.value ()));
1489  }
1490 
1491  void
1493  {
1494  llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
1495  Complex value = cc.value ();
1496  llvm::Value *real = llvm::ConstantFP::get (scalar_t, value.real ());
1497  llvm::Value *imag = llvm::ConstantFP::get (scalar_t, value.imag ());
1498  cc.stash_llvm (jit_typeinfo::create_complex (real, imag));
1499  }
1500 
1502  {
1503  ci.stash_llvm (llvm::ConstantInt::get (ci.type_llvm (), ci.value ()));
1504  }
1505 
1506  void
1508  {
1509  llvm::StructType *stype = llvm::cast<llvm::StructType>(cr.type_llvm ());
1510  llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm ();
1511  llvm::Type *idx = jit_typeinfo::get_index_llvm ();
1512  const jit_range& rng = cr.value ();
1513 
1514  llvm::Constant *constants[4];
1515  constants[0] = llvm::ConstantFP::get (scalar_t, rng.m_base);
1516  constants[1] = llvm::ConstantFP::get (scalar_t, rng.m_limit);
1517  constants[2] = llvm::ConstantFP::get (scalar_t, rng.m_inc);
1518  constants[3] = llvm::ConstantInt::get (idx, rng.m_nelem);
1519 
1520  llvm::Value *as_llvm;
1521  as_llvm = llvm::ConstantStruct::get (stype,
1522  llvm::makeArrayRef (constants, 4));
1523  cr.stash_llvm (as_llvm);
1524  }
1525 
1526  void
1528  {
1529  llvm::BasicBlock *m_block = b.to_llvm ();
1530  builder.SetInsertPoint (m_block);
1531  for (auto iter = b.begin (); iter != b.end (); ++iter)
1532  visit (*iter);
1533  }
1534 
1535  void
1537  {
1538  b.stash_llvm (builder.CreateBr (b.successor_llvm ()));
1539  }
1540 
1541  void
1543  {
1544  llvm::Value *cond = cb.cond_llvm ();
1545  llvm::Value *br;
1546  br = builder.CreateCondBr (cond, cb.successor_llvm (0),
1547  cb.successor_llvm (1));
1548  cb.stash_llvm (br);
1549  }
1550 
1551  void
1553  {
1554  const jit_function& ol = call.overload ();
1555 
1556  std::vector<jit_value *> args (call.arguments ().size ());
1557  for (size_t i = 0; i < args.size (); ++i)
1558  args[i] = call.argument (i);
1559 
1560  llvm::Value *ret = ol.call (builder, args);
1561  call.stash_llvm (ret);
1562  }
1563 
1564  void
1566  {
1567  llvm::Value *arg = m_arguments[extract.name ()];
1568  assert (arg);
1569 
1571  extract.stash_llvm (arg);
1572  else
1573  {
1574  arg = builder.CreateLoad (arg);
1575 
1576  const jit_function& ol = extract.overload ();
1577  extract.stash_llvm (ol.call (builder, arg));
1578  }
1579  }
1580 
1581  void
1583  {
1584  const jit_function& ol = store.overload ();
1585  llvm::Value *arg_value = ol.call (builder, store.result ());
1586  llvm::Value *arg = m_arguments[store.name ()];
1587  store.stash_llvm (builder.CreateStore (arg_value, arg));
1588  }
1589 
1590  void
1592  {
1593  jit_value *res = ret.result ();
1594 
1596  m_creating.do_return (builder, res->to_llvm (), false);
1597  else
1598  {
1599  if (res)
1600  builder.CreateRet (res->to_llvm ());
1601  else
1602  builder.CreateRetVoid ();
1603  }
1604  }
1605 
1606  void
1608  {
1609  // we might not have converted all incoming branches, so we don't
1610  // set incoming branches now
1611  llvm::PHINode *node = llvm::PHINode::Create (phi.type_llvm (),
1612  phi.argument_count ());
1613  builder.Insert (node);
1614  phi.stash_llvm (node);
1615  }
1616 
1617  void
1619  {
1620  throw jit_fail_exception ("ERROR: SSA construction should remove all variables");
1621  }
1622 
1623  void
1625  {
1626  llvm::Value *cond;
1627 
1628  switch (check.check_variable ())
1629  {
1632  break;
1635  break;
1636  default:
1637  panic_impossible ();
1638  }
1639 
1640  llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0),
1641  check.successor_llvm (1));
1642  check.stash_llvm (br);
1643  }
1644 
1645  void
1647  {
1648  jit_value *new_value = assign.src ();
1649  assign.stash_llvm (new_value->to_llvm ());
1650 
1651  if (assign.artificial ())
1652  return;
1653 
1654  jit_value *overwrite = assign.overwrite ();
1655  if (isa<jit_assign_base> (overwrite))
1656  {
1657  const jit_function& ol = jit_typeinfo::get_release (overwrite->type ());
1658  if (ol.valid ())
1659  ol.call (builder, overwrite);
1660  }
1661  }
1662 
1663  void
1665  { }
1666 
1667  void
1669  {
1670  const jit_function& ol = me.overload ();
1671 
1673  llvm::Value *ret = ol.call (builder, ctx.m_value, ctx.m_index,
1674  ctx.m_count);
1675  me.stash_llvm (ret);
1676  }
1677 
1678  // -------------------- jit_infer --------------------
1680  const variable_map& avmap)
1681  : m_blocks (ablocks), m_factory (afactory), m_vmap (avmap) { }
1682 
1683  void
1685  {
1686  construct_ssa ();
1687 
1688  // initialize the worklist to instructions derived from constants
1689  const std::list<jit_value *>& constants = m_factory.constants ();
1690  for (auto iter = constants.begin (); iter != constants.end (); ++iter)
1691  append_users (*iter);
1692 
1693  // the entry block terminator may be a regular branch statement
1694  if (entry_block ().terminator ())
1695  push_worklist (entry_block ().terminator ());
1696 
1697  // FIXME: Describe algorithm here
1698  while (m_worklist.size ())
1699  {
1700  jit_instruction *next = m_worklist.front ();
1701  m_worklist.pop_front ();
1702  next->stash_in_worklist (false);
1703 
1704  if (next->infer ())
1705  {
1706  // terminators need to be handles specially
1707  if (jit_terminator *term = dynamic_cast<jit_terminator *> (next))
1708  append_users_term (term);
1709  else
1710  append_users (next);
1711  }
1712  }
1713 
1714  remove_dead ();
1715  m_blocks.label ();
1716  place_releases ();
1717  simplify_phi ();
1718  }
1719 
1720  void
1722  {
1723  for (jit_use *use = v->first_use (); use; use = use->next ())
1724  push_worklist (use->user ());
1725  }
1726 
1727  void
1729  {
1730  for (size_t i = 0; i < term->successor_count (); ++i)
1731  {
1732  if (term->alive (i))
1733  {
1734  jit_block *succ = term->successor (i);
1735  for (auto iter = succ->begin ();
1736  iter != succ->end () && isa<jit_phi> (*iter); ++iter)
1737  push_worklist (*iter);
1738 
1739  jit_terminator *sterm = succ->terminator ();
1740  if (sterm)
1741  push_worklist (sterm);
1742  }
1743  }
1744  }
1745 
1746  void
1748  {
1749  m_blocks.label ();
1751  entry_block ().compute_df ();
1753 
1754  // insert phi nodes where needed, this is done on a per variable basis
1755  for (auto iter = m_vmap.cbegin (); iter != m_vmap.cend (); ++iter)
1756  {
1757  jit_block::df_set visited, added_phi;
1758  std::list<jit_block *> ssa_worklist;
1759  iter->second->use_blocks (visited);
1760  ssa_worklist.insert (ssa_worklist.begin (), visited.begin (),
1761  visited.end ());
1762 
1763  while (ssa_worklist.size ())
1764  {
1765  jit_block *b = ssa_worklist.front ();
1766  ssa_worklist.pop_front ();
1767 
1768  for (auto diter = b->df_begin (); diter != b->df_end (); ++diter)
1769  {
1770  jit_block *dblock = *diter;
1771  if (! added_phi.count (dblock))
1772  {
1773  jit_phi *phi = m_factory.create<jit_phi> (iter->second,
1774  dblock->use_count ());
1775  dblock->prepend (phi);
1776  added_phi.insert (dblock);
1777  }
1778 
1779  if (! visited.count (dblock))
1780  {
1781  ssa_worklist.push_back (dblock);
1782  visited.insert (dblock);
1783  }
1784  }
1785  }
1786  }
1787 
1788  do_construct_ssa (entry_block (), entry_block ().visit_count ());
1789  }
1790 
1791  void
1792  jit_infer::do_construct_ssa (jit_block& ablock, size_t avisit_count)
1793  {
1794  if (ablock.visited (avisit_count))
1795  return;
1796 
1797  // replace variables with their current SSA value
1798  for (auto iter = ablock.begin (); iter != ablock.end (); ++iter)
1799  {
1800  jit_instruction *instr = *iter;
1801  instr->construct_ssa ();
1802  instr->push_variable ();
1803  }
1804 
1805  // finish phi nodes of successors
1806  for (size_t i = 0; i < ablock.successor_count (); ++i)
1807  {
1808  jit_block *finish = ablock.successor (i);
1809 
1810  for (auto iter = finish->begin ();
1811  iter != finish->end () && isa<jit_phi> (*iter);)
1812  {
1813  jit_phi *phi = static_cast<jit_phi *> (*iter);
1814  jit_variable *var = phi->dest ();
1815  ++iter;
1816 
1817  if (var->has_top ())
1818  phi->add_incoming (&ablock, var->top ());
1819  else
1820  {
1821  // temporaries may have extraneous phi nodes which can be
1822  // removed
1823  assert (! phi->use_count ());
1824  assert (var->name ().size () && var->name ()[0] == '#');
1825  phi->remove ();
1826  }
1827  }
1828  }
1829 
1830  for (size_t i = 0; i < ablock.dom_successor_count (); ++i)
1831  do_construct_ssa (*ablock.dom_successor (i), avisit_count);
1832 
1833  ablock.pop_all ();
1834  }
1835 
1836  void
1838  {
1839  std::set<jit_value *> temporaries;
1840  for (auto iter = m_blocks.begin (); iter != m_blocks.end (); ++iter)
1841  {
1842  jit_block& ablock = **iter;
1843  if (ablock.id () != jit_block::NO_ID)
1844  {
1845  release_temp (ablock, temporaries);
1846  release_dead_phi (ablock);
1847  }
1848  }
1849  }
1850 
1851  void
1853  {
1854  if (! instr->in_worklist ())
1855  {
1856  instr->stash_in_worklist (true);
1857  m_worklist.push_back (instr);
1858  }
1859  }
1860 
1861  void
1863  {
1865  for (biter = m_blocks.begin (); biter != m_blocks.end (); ++biter)
1866  {
1867  jit_block *b = *biter;
1868  if (b->alive ())
1869  {
1870  for (auto iter = b->begin ();
1871  iter != b->end () && isa<jit_phi> (*iter);)
1872  {
1873  jit_phi *phi = static_cast<jit_phi *> (*iter);
1874  if (phi->prune ())
1875  iter = b->remove (iter);
1876  else
1877  ++iter;
1878  }
1879  }
1880  }
1881 
1882  for (biter = m_blocks.begin (); biter != m_blocks.end ();)
1883  {
1884  jit_block *b = *biter;
1885  if (b->alive ())
1886  {
1887  // FIXME: A special case for jit_error_check, if we generalize to
1888  // we will need to change!
1889  jit_terminator *term = b->terminator ();
1890  if (term && term->successor_count () == 2 && ! term->alive (0))
1891  {
1892  jit_block *succ = term->successor (1);
1893  term->remove ();
1894  jit_branch *abreak = m_factory.create<jit_branch> (succ);
1895  b->append (abreak);
1896  abreak->infer ();
1897  }
1898 
1899  ++biter;
1900  }
1901  else
1902  {
1903  jit_terminator *term = b->terminator ();
1904  if (term)
1905  term->remove ();
1906  biter = m_blocks.erase (biter);
1907  }
1908  }
1909  }
1910 
1911  void
1913  {
1914  auto iter = ablock.begin ();
1915  while (iter != ablock.end () && isa<jit_phi> (*iter))
1916  {
1917  jit_phi *phi = static_cast<jit_phi *> (*iter);
1918  ++iter;
1919 
1920  jit_use *use = phi->first_use ();
1921  if (phi->use_count () == 1 && isa<jit_assign> (use->user ()))
1922  {
1923  // instead of releasing on assign, release on all incoming
1924  // branches, this can get rid of casts inside loops
1925  for (size_t i = 0; i < phi->argument_count (); ++i)
1926  {
1927  jit_value *arg = phi->argument (i);
1928  if (! arg->needs_release ())
1929  continue;
1930 
1931  jit_block *inc = phi->incoming (i);
1932  jit_block *split = inc->maybe_split (m_factory, m_blocks,
1933  ablock);
1934  jit_terminator *term = split->terminator ();
1935  jit_call *release
1937  release->infer ();
1938  split->insert_before (term, release);
1939  }
1940 
1941  phi->replace_with (0);
1942  phi->remove ();
1943  }
1944  }
1945  }
1946 
1947  void
1948  jit_infer::release_temp (jit_block& ablock, std::set<jit_value *>& temp)
1949  {
1950  for (auto iter = ablock.begin (); iter != ablock.end (); ++iter)
1951  {
1952  jit_instruction *instr = *iter;
1953 
1954  // check for temporaries that require release and live across
1955  // multiple blocks
1956  if (instr->needs_release ())
1957  {
1958  jit_block *fu_block = instr->first_use_block ();
1959  if (fu_block && fu_block != &ablock && instr->needs_release ())
1960  temp.insert (instr);
1961  }
1962 
1963  if (isa<jit_call> (instr))
1964  {
1965  // place releases for temporary arguments
1966  for (size_t i = 0; i < instr->argument_count (); ++i)
1967  {
1968  jit_value *arg = instr->argument (i);
1969  if (! arg->needs_release ())
1970  continue;
1971 
1972  jit_call *release
1974  release->infer ();
1975  ablock.insert_after (iter, release);
1976  ++iter;
1977  temp.erase (arg);
1978  }
1979  }
1980  }
1981 
1982  if (! temp.size () || ! isa<jit_error_check> (ablock.terminator ()))
1983  return;
1984 
1985  // FIXME: If we support try/catch or unwind_protect final_block
1986  // may not be the destination
1987  jit_block *split = ablock.maybe_split (m_factory, m_blocks,
1988  final_block ());
1989  jit_terminator *term = split->terminator ();
1990  for (auto iter = temp.cbegin (); iter != temp.cend (); ++iter)
1991  {
1992  jit_value *value = *iter;
1993  jit_call *release
1995  split->insert_before (term, release);
1996  release->infer ();
1997  }
1998  }
1999 
2000  void
2002  {
2003  for (auto biter = m_blocks.begin (); biter != m_blocks.end (); ++biter)
2004  {
2005  jit_block &ablock = **biter;
2006  for (auto iter = ablock.begin ();
2007  iter != ablock.end () && isa<jit_phi> (*iter); ++iter)
2008  simplify_phi (*static_cast<jit_phi *> (*iter));
2009  }
2010  }
2011 
2012  void
2014  {
2015  jit_block& pblock = *phi.parent ();
2016  const jit_operation& cast_fn = jit_typeinfo::cast (phi.type ());
2017  jit_variable *dest = phi.dest ();
2018  for (size_t i = 0; i < phi.argument_count (); ++i)
2019  {
2020  jit_value *arg = phi.argument (i);
2021  if (arg->type () != phi.type ())
2022  {
2023  jit_block *pred = phi.incoming (i);
2024  jit_block *split = pred->maybe_split (m_factory, m_blocks, pblock);
2025  jit_terminator *term = split->terminator ();
2026  jit_instruction *cast = m_factory.create<jit_call> (cast_fn, arg);
2027  jit_assign *assign = m_factory.create<jit_assign> (dest, cast);
2028 
2029  split->insert_before (term, cast);
2030  split->insert_before (term, assign);
2031  cast->infer ();
2032  assign->infer ();
2033  phi.stash_argument (i, assign);
2034  }
2035  }
2036  }
2037 
2038 
2039  // ---------------- jit_memory_manager ------------------
2040 
2041  // A simple memory manager for our LLVM engines,
2042  // based on LLVM's Kaleidoscope example
2043 
2044  class jit_memory_manager : public llvm::SectionMemoryManager
2045  {
2047  void operator= (const jit_memory_manager&) = delete;
2048  public:
2050  virtual ~jit_memory_manager () { }
2051 
2052  // The Kaleidoscope example in LLVM 3.8 indicates that
2053  // getPointerToNamedFunction has to be overloaded, but actually it is
2054  // getSymbolAddress that must be overloaded.
2055  virtual uint64_t getSymbolAddress (const std::string &name);
2056 
2057  // Is it still useful to overload getPointerToNamedFunction to support
2058  // some older version of LLVM? Are there others virtual functions
2059  // that must be overloaded?
2060  virtual void* getPointerToNamedFunction (const std::string& name, bool
2061  abort_on_failure);
2062  };
2063 
2064  void*
2066  bool abort_on_failure)
2067  {
2068  // Try the standard symbol resolution first, but ask it not to abort
2069  void *pfn = llvm::RTDyldMemoryManager::getPointerToNamedFunction (name,
2070  false);
2071  if (pfn)
2072  return pfn;
2073 
2075  if ((pfn == nullptr) && abort_on_failure)
2076  llvm::report_fatal_error ("Program used external function '" + name +
2077  "' which could not be resolved!");
2078  return pfn;
2079  }
2080 
2081  uint64_t
2083  {
2084  uint64_t addr = llvm::SectionMemoryManager::getSymbolAddress (name);
2085  if (addr)
2086  return addr;
2087 
2089  if (addr == 0)
2090  llvm::report_fatal_error ("Program used extern function '" + name +
2091  "' which could not be resolved!");
2092 
2093  return addr;
2094  }
2095 
2096 
2097  // -------------------- tree_jit --------------------
2098 
2099  bool tree_jit::initialized = false;
2100 
2101  llvm::LLVMContext tree_jit::llvm_context;
2102 
2106 
2108  : target_machine (nullptr)
2109  {
2110  // target_machine will be truly initialized by tree_jit::do_initialize ()
2111  }
2112 
2114  {
2115  delete target_machine;
2116  }
2117 
2118  tree_jit&
2120  {
2121  static tree_jit ret; // singleton instance of tree_jit
2122 
2123  if (! initialized)
2124  // Try to initialize the singleton instance
2125  ret.do_initialize ();
2126 
2127  return ret;
2128  }
2129 
2132  {
2133  std::string err;
2134 
2135  llvm::ExecutionEngine *e = llvm::EngineBuilder (std::move (module_owner))
2136  .setErrorStr (&err)
2137  .setMCJITMemoryManager(llvm::make_unique<jit_memory_manager> ())
2138  .create ();
2139 
2140  // Note: in some versions of LLVM, we should call .setUseMCJIT (true)
2141  // before .create () ?
2142  // FIXME: autconf this
2143 
2144  if (e == nullptr)
2145  error ("failed to create JIT engine: %s", err.c_str ());
2146 
2147  return jit::EngineOwner (e);
2148  }
2149 
2150  void
2152  {
2153  jm_list.push_back (jm);
2154  }
2155 
2156  void
2158  {
2159  jm_list.remove (jm);
2160  }
2161 
2162  void*
2164  {
2165  std::list<jit_module*>::const_iterator it;
2166 
2167  for (it = jm_list.begin (); it != jm_list.end (); it++)
2168  {
2169  uint64_t addr = (*it)->getFunctionAddress (name);
2170 
2171  if (addr)
2172  return reinterpret_cast<void*> (addr);
2173  }
2174 
2175  return nullptr;
2176  }
2177 
2178  uint64_t
2179  tree_jit::do_getSymbolAddress(const std::string &name) const
2180  {
2181  std::list<jit_module*>::const_iterator it;
2182 
2183  for (it = jm_list.begin (); it != jm_list.end (); it++)
2184  {
2185  uint64_t addr = (*it)->getFunctionAddress (name);
2186 
2187  if (addr)
2188  return addr;
2189  }
2190 
2191  return 0;
2192  }
2193 
2194  bool
2196  {
2197  if (initialized)
2198  return true;
2199 
2200  llvm::InitializeNativeTarget ();
2201  llvm::InitializeNativeTargetAsmPrinter ();
2202  llvm::InitializeNativeTargetAsmParser ();
2203  // FIXME: Check that these three initializations succeed
2204 
2205  if (target_machine == nullptr)
2206  {
2207  target_machine = llvm::EngineBuilder ().selectTarget ();
2208  if (target_machine == nullptr)
2209  return false;
2210  }
2211 
2212  return (initialized = true);
2213  }
2214 
2216  tree_jit::open_new_module (const std::string& module_name)
2217  {
2218  return instance ().do_open_new_module (module_name);
2219  }
2220 
2222  tree_jit::do_open_new_module (const std::string& module_name) const
2223  {
2224  if (! initialized)
2225  return nullptr;
2226 
2227  jit::ModuleOwner m (new llvm::Module (module_name, context));
2228 
2229 
2230  if (m != nullptr)
2231  m->setDataLayout (target_machine->createDataLayout ());
2232 
2233  return m;
2234  }
2235 
2236  bool
2238  const octave_value& bounds)
2239  {
2240  size_t tc = trip_count (bounds);
2241  if (! tc || ! initialized || ! enabled ())
2242  return false;
2243 
2244  jit_info::vmap extra_vars;
2245  extra_vars["#for_bounds0"] = &bounds;
2246 
2247  jit_info *info = cmd.get_info ();
2248 
2249  if (! info || ! info->match (extra_vars))
2250  {
2251  if (tc < static_cast<size_t> (Vjit_startcnt))
2252  return false;
2253 
2254  delete info;
2255 
2256  info = new jit_info (cmd, bounds);
2257 
2258  cmd.stash_info (info);
2259  }
2260 
2261  return info->execute (extra_vars);
2262  }
2263 
2264  bool
2266  {
2267  if (! initialized || ! enabled ())
2268  return false;
2269 
2270  jit_info *info = cmd.get_info ();
2271  if (! info || ! info->match ())
2272  {
2273  delete info;
2274  info = new jit_info (cmd);
2275  cmd.stash_info (info);
2276  }
2277 
2278  return info->execute ();
2279  }
2280 
2281  bool
2283  const octave_value_list& args,
2285  {
2286  if (! initialized || ! enabled ())
2287  return false;
2288 
2289  jit_function_info *info = fcn.get_info ();
2290  if (! info || ! info->match (args))
2291  {
2292  delete info;
2293  info = new jit_function_info (fcn, args);
2294  fcn.stash_info (info);
2295  }
2296 
2297  return info->execute (args, retval);
2298  }
2299 
2300  bool
2302  {
2303  bp_table& bptab = __get_bp_table__ ("tree_jit::enabled");
2304 
2305  // Ideally, we should only disable JIT if there is a breakpoint in the code
2306  // we are about to run. However, we can't figure this out in O(1) time, so
2307  // we conservatively check for the existence of any breakpoints.
2308  return (Vjit_enable && ! bptab.have_breakpoints ()
2309  && ! Vdebug_on_interrupt && ! Vdebug_on_error);
2310  }
2311 
2312  size_t
2313  tree_jit::trip_count (const octave_value& bounds) const
2314  {
2315  if (bounds.is_range ())
2316  {
2317  Range rng = bounds.range_value ();
2318  return rng.numel ();
2319  }
2320 
2321  // unsupported type
2322  return 0;
2323  }
2324 
2325 
2326  // -------------------- jit_module --------------------
2327 
2328  jit_module::jit_module (const std::string& module_name)
2329  : m_module (nullptr), m_engine (nullptr)
2330  {
2331  jit::ModuleOwner module_owner = tree_jit::open_new_module (module_name);
2332  // FIXME: what if this fails? exception?
2333 
2334  // Get a pointer to the module before ownership is transferred to engine
2335  m_module = module_owner.get ();
2336 
2337  jit::EngineOwner engine_owner = std::move
2338  (tree_jit::create_new_engine (std::move (module_owner)));
2339  // FIXME: what if this fails? exception?
2340 
2341  // TODO?: Consider creating the engine just before jitting
2342 
2343  // We take responsibility for deleting the engine
2344  m_engine = engine_owner.get ();
2345  engine_owner.release ();
2346 
2348  }
2349 
2351  {
2353 
2354  delete m_engine;
2355  }
2356 
2357  // Create an LLVM function in the module, with external linkage
2358  llvm::Function*
2359  jit_module::create_llvm_function (llvm::FunctionType *ftype,
2360  const llvm::Twine &name) const
2361  {
2362  // we mark all functinos as external linkage because this prevents
2363  // llvm from getting rid of always inline functions
2364 
2365  return llvm::Function::Create (ftype, llvm::Function::ExternalLinkage,
2366  name, m_module);
2367  }
2368 
2369  // Create or insert an LLVM Function declaration for an intrinsic and return
2370  // it
2371  llvm::Function*
2373  std::vector<llvm::Type*> types) const
2374  {
2375  return llvm::Intrinsic::getDeclaration
2376  (m_module, static_cast<llvm::Intrinsic::ID> (id), types);
2377  }
2378 
2379  // Create a global in the module
2380  llvm::GlobalVariable*
2381  jit_module::create_global_variable (llvm::Type *type, bool is_constant,
2382  const llvm::Twine& name) const
2383  {
2384  return new llvm::GlobalVariable (*m_module, type, is_constant,
2385  llvm::GlobalValue::ExternalLinkage,
2386  nullptr, name);
2387  }
2388 
2389  void
2390  jit_module::do_add_global_mapping (const llvm::GlobalValue* gv, void* p) const
2391  {
2392  assert (gv);
2393  m_engine->addGlobalMapping (gv, p);
2394  }
2395 
2396  // Return the address of the specified function.
2397  uint64_t
2398  jit_module::getFunctionAddress (const std::string &name) const
2399  {
2400  return m_engine->getFunctionAddress (name);
2401  }
2402 
2403  void
2404  jit_module::optimize (llvm::Function *fn) const
2405  {
2406  if (Vdebug_jit)
2407  llvm::verifyModule (*m_module);
2408 
2409  // DOCUMENT-ME: Why do we need two separate pass managers?
2410 
2411  jit::PassManager *module_pass_manager = new jit::PassManager ();
2413 
2414 #if defined (LLVM_HAS_CREATEALWAYSINLINERPASS)
2415  // This pass has been removed from LLVM's C++ API after 3.9.0
2416  // FIXME: Provide a meaningful replacement instead of simply skipping it?
2417  module_pass_manager->add (llvm::createAlwaysInlinerPass ());
2418 #endif
2419 
2420  // In 3.6, a pass was inserted in the pipeline to make the DataLayout accessible:
2421  // MyPassManager->add(new DataLayoutPass(MyTargetMachine->getDataLayout()));
2422  // In 3.7, you don’t need a pass, you set the DataLayout on the Module:
2423  // MyModule->setDataLayout(MyTargetMachine->createDataLayout());
2424  //
2425  // FIXME: autoconf to support <= 3.6
2426  //
2427  // #if defined (HAVE_LLVM_DATALAYOUT)
2428  // pass_manager->add (new llvm::DataLayout (*m_engine->getDataLayout ()));
2429  // #else
2430  // // For very old LLVM releases ???
2431  // pass_manager->add (new llvm::TargetData (*m_engine->getTargetData ()));
2432  // #endif
2433 
2434  // DOCUMENT-ME: What does each of these passes actually do?
2435 
2436  pass_manager->add (llvm::createCFGSimplificationPass ());
2437 
2438 #if defined (HAVE_LLVM_ANALYSIS_BASICALIASANALYSIS_H)
2439  pass_manager->add (llvm::createBasicAAWrapperPass ());
2440 #else
2441  pass_manager->add (llvm::createBasicAliasAnalysisPass ());
2442 #endif
2443 
2444  pass_manager->add (llvm::createPromoteMemoryToRegisterPass ());
2445  pass_manager->add (llvm::createInstructionCombiningPass ());
2446  pass_manager->add (llvm::createReassociatePass ());
2447  pass_manager->add (llvm::createGVNPass ());
2448  pass_manager->add (llvm::createCFGSimplificationPass ());
2449  pass_manager->doInitialization ();
2450 
2451  module_pass_manager->run (*m_module);
2452  pass_manager->run (*fn);
2453 
2454  delete module_pass_manager;
2455  delete pass_manager;
2456 
2457  if (Vdebug_jit)
2458  {
2459  // This should be OK in LLVM 3.6 -- 3.8 (and later ?)
2460  std::error_code ec;
2461  llvm::raw_fd_ostream fout ("test.bc", ec, llvm::sys::fs::F_None);
2462 
2463  // std::string error;
2464  //#if defined (RAW_FD_OSTREAM_ARG_IS_LLVM_SYS_FS)
2465  // llvm::raw_fd_ostream fout ("test.bc", error, llvm::sys::fs::F_Binary);
2466  //#else
2467  // llvm::raw_fd_ostream fout ("test.bc", error, llvm::raw_fd_ostream::F_Binary);
2468  //#endif
2469 
2470  llvm::WriteBitcodeToFile (m_module, fout);
2471  }
2472  }
2473 
2474  void
2476  {
2477  m_engine->finalizeObject ();
2478  }
2479 
2480 
2481  // -------------------- jit_function_info --------------------
2483  const octave_value_list& ov_args)
2484  : m_llvm_function_name (""),
2485  m_function (nullptr),
2486  m_argument_types (ov_args.length ())
2487  {
2488  size_t nargs = ov_args.length ();
2489  for (size_t i = 0; i < nargs; ++i)
2490  m_argument_types[i] = jit_typeinfo::type_of (ov_args(i));
2491 
2492  jit_function raw_fn;
2493  jit_function wrapper;
2494 
2495  try
2496  {
2497  jit_convert conv (fcn, m_argument_types);
2498  jit_infer infer (conv.get_factory (), conv.get_blocks (),
2499  conv.get_variable_map ());
2500  infer.infer ();
2501 
2502  if (Vdebug_jit)
2503  {
2504  jit_block_list& blocks = infer.get_blocks ();
2505  blocks.label ();
2506  octave_stdout << "-------------------- Compiling function ";
2507  octave_stdout << "--------------------\n";
2508 
2511  tpc.visit_statement_list (*fcn.body ());
2513  blocks.print (octave_stdout, "octave jit ir");
2514  }
2515 
2516  jit_factory& factory = conv.get_factory ();
2517  jit_convert_llvm to_llvm;
2518  raw_fn = to_llvm.convert_function (*this, infer.get_blocks (),
2519  factory.constants (), fcn,
2521 
2522  if (Vdebug_jit)
2523  {
2524  octave_stdout << "-------------------- raw function ";
2525  octave_stdout << "--------------------\n";
2526  octave_stdout << *raw_fn.to_llvm () << std::endl;
2527  llvm::verifyFunction (*raw_fn.to_llvm ());
2528  }
2529 
2530  m_llvm_function_name = fcn.name () + "_wrapper";
2531  jit_type *any_t = jit_typeinfo::get_any ();
2532  std::vector<jit_type *> wrapper_args (1, jit_typeinfo::get_any_ptr ());
2533  wrapper = jit_function (this, jit_convention::internal,
2534  m_llvm_function_name, any_t, wrapper_args);
2535 
2536  llvm::BasicBlock *wrapper_body = wrapper.new_block ();
2537  builder.SetInsertPoint (wrapper_body);
2538 
2539  llvm::Value *wrapper_arg = wrapper.argument (builder, 0);
2540  std::vector<llvm::Value *> raw_args (nargs);
2541  for (size_t i = 0; i < nargs; ++i)
2542  {
2543  llvm::Value *arg;
2544  // LLVM <= 3.6
2545  // arg = builder.CreateConstInBoundsGEP1_32 (wrapper_arg, i);
2546  // LLVM >= 3.7
2547  arg = builder.CreateConstInBoundsGEP1_32 (any_t->to_llvm (),
2548  wrapper_arg, i);
2549 
2550  arg = builder.CreateLoad (arg);
2551 
2552  jit_type *arg_type = m_argument_types[i];
2553  const jit_function& cast = jit_typeinfo::cast (arg_type, any_t);
2554  raw_args[i] = cast.call (builder, arg);
2555  }
2556 
2557  llvm::Value *result = raw_fn.call (builder, raw_args);
2558  if (raw_fn.result ())
2559  {
2560  jit_type *raw_result_t = raw_fn.result ();
2561  const jit_function& cast = jit_typeinfo::cast (any_t,
2562  raw_result_t);
2563  result = cast.call (builder, result);
2564  }
2565  else
2566  {
2567  llvm::Value *zero = builder.getInt32 (0);
2568  result = builder.CreateBitCast (zero, any_t->to_llvm ());
2569  }
2570 
2571  wrapper.do_return (builder, result);
2572 
2573  llvm::Function *llvm_function = wrapper.to_llvm ();
2574  optimize (llvm_function);
2575 
2576  if (Vdebug_jit)
2577  {
2578  octave_stdout << "-------------------- optimized and wrapped ";
2579  octave_stdout << "--------------------\n";
2580  octave_stdout << *llvm_function << std::endl;
2581  llvm::verifyFunction (*llvm_function);
2582  }
2583 
2584  finalizeObject ();
2585 
2586  uint64_t void_fn = getFunctionAddress (m_llvm_function_name);
2587 
2588  if (void_fn == 0)
2589  {
2590  llvm_function->eraseFromParent ();
2591  llvm_function = nullptr;
2592  m_function = nullptr;
2593  }
2594  else
2595  {
2596  m_function = reinterpret_cast<jited_function> (void_fn);
2597  }
2598  }
2599  catch (const jit_fail_exception& e)
2600  {
2601  m_argument_types.clear ();
2602 
2603  if (Vdebug_jit)
2604  {
2605  if (e.known ())
2606  octave_stdout << "jit fail: " << e.what () << std::endl;
2607  }
2608 
2609  Vjit_failcnt++;
2610 
2611  wrapper.erase ();
2612  raw_fn.erase ();
2613  }
2614  }
2615 
2616  bool
2618  octave_value_list& retval) const
2619  {
2620  if (! m_function)
2621  return false;
2622 
2623  // FIXME: figure out a way to delete ov_args so we avoid duplicating
2624  // refcount
2625  size_t nargs = ov_args.length ();
2626  std::vector<octave_base_value *> args (nargs);
2627  for (size_t i = 0; i < nargs; ++i)
2628  {
2629  octave_base_value *obv = ov_args(i).internal_rep ();
2630  obv->grab ();
2631  args[i] = obv;
2632  }
2633 
2634  octave_base_value *ret = m_function (&args[0]);
2635  if (ret)
2636  retval(0) = octave_value (ret);
2637 
2638  octave_quit ();
2639 
2640  return true;
2641  }
2642 
2643  bool
2645  {
2646  if (! m_function)
2647  return true;
2648 
2649  size_t nargs = ov_args.length ();
2650  if (nargs != m_argument_types.size ())
2651  return false;
2652 
2653  for (size_t i = 0; i < nargs; ++i)
2654  if (jit_typeinfo::type_of (ov_args(i)) != m_argument_types[i])
2655  return false;
2656 
2657  return true;
2658  }
2659 
2660 
2661  // -------------------- jit_info --------------------
2663  : m_llvm_function_name (tree_jit::generate_unique_function_name ()),
2664  m_function (nullptr)
2665  {
2666  compile (tee);
2667  }
2668 
2669  jit_info::jit_info (tree& tee, const octave_value& for_bounds)
2670  : m_llvm_function_name (tree_jit::generate_unique_function_name ()),
2671  m_function (nullptr)
2672  {
2673  compile (tee, jit_typeinfo::type_of (for_bounds));
2674  }
2675 
2677  const octave_value& for_bounds)
2678  : m_llvm_function_name (tree_jit::generate_unique_forloop_name ()),
2679  m_function (nullptr)
2680  {
2681  compile (tee, jit_typeinfo::type_of (for_bounds));
2682  }
2683 
2684  bool
2685  jit_info::execute (const vmap& extra_vars) const
2686  {
2687  if (! m_function)
2688  return false;
2689 
2690  std::vector<octave_base_value *> real_arguments (m_arguments.size ());
2691  for (size_t i = 0; i < m_arguments.size (); ++i)
2692  {
2693  if (m_arguments[i].second)
2694  {
2695  octave_value current = find (extra_vars, m_arguments[i].first);
2696  octave_base_value *obv = current.internal_rep ();
2697 
2698  obv->grab ();
2699 
2700  real_arguments[i] = obv;
2701  }
2702  }
2703 
2704  m_function (&real_arguments[0]);
2705 
2706  symbol_scope scope = __require_current_scope__ ("jit_info::execute");
2707 
2708  for (size_t i = 0; i < m_arguments.size (); ++i)
2709  {
2710  const std::string& name = m_arguments[i].first;
2711 
2712  // do not store for loop bounds temporary
2713  if (name.size () && name[0] != '#')
2714  scope.assign (m_arguments[i].first, real_arguments[i]);
2715  }
2716 
2717  octave_quit ();
2718 
2719  return true;
2720  }
2721 
2722  bool
2723  jit_info::match (const vmap& extra_vars) const
2724  {
2725  if (! m_function)
2726  return true;
2727 
2728  for (size_t i = 0; i < m_bounds.size (); ++i)
2729  {
2730  const std::string& arg_name = m_bounds[i].second;
2731  octave_value value = find (extra_vars, arg_name);
2732  jit_type *type = jit_typeinfo::type_of (value);
2733 
2734  // FIXME: Check for a parent relationship
2735  if (type != m_bounds[i].first)
2736  return false;
2737  }
2738 
2739  return true;
2740  }
2741 
2742  void
2743  jit_info::compile (tree& tee, jit_type *for_bounds)
2744  {
2745  llvm::Function * llvm_function = nullptr;
2746 
2747  try
2748  {
2749  jit_convert conv (tee, for_bounds);
2750  jit_infer infer (conv.get_factory (), conv.get_blocks (),
2751  conv.get_variable_map ());
2752 
2753  infer.infer ();
2754 
2755  if (Vdebug_jit)
2756  {
2757  jit_block_list& blocks = infer.get_blocks ();
2758  blocks.label ();
2759  octave_stdout << "-------------------- Compiling tree --------------------\n";
2760  octave_stdout << tee.str_print_code () << std::endl;
2761  blocks.print (octave_stdout, "octave jit ir");
2762  }
2763 
2764  jit_factory& factory = conv.get_factory ();
2765  jit_convert_llvm to_llvm;
2766 
2767  llvm_function = to_llvm.convert_loop (*this, infer.get_blocks (),
2768  factory.constants (),
2770 
2771  m_arguments = to_llvm.get_arguments ();
2772 
2773  m_bounds = conv.get_bounds ();
2774  }
2775  catch (const jit_fail_exception& e)
2776  {
2777  if (Vdebug_jit)
2778  {
2779  if (e.known ())
2780  octave_stdout << "jit fail: " << e.what () << std::endl;
2781  }
2782 
2783  Vjit_failcnt++;
2784 
2785  }
2786 
2787  if (llvm_function)
2788  {
2789  if (Vdebug_jit)
2790  {
2791  octave_stdout << "-------------------- llvm ir --------------------";
2792  octave_stdout << *llvm_function << std::endl;
2793  llvm::verifyFunction (*llvm_function);
2794  }
2795 
2796  optimize (llvm_function);
2797 
2798  if (Vdebug_jit)
2799  {
2800  octave_stdout << "-------------------- optimized llvm ir "
2801  << "--------------------\n";
2802  octave_stdout << *llvm_function << std::endl;
2803  }
2804 
2805  finalizeObject ();
2806 
2807  uint64_t void_fn = getFunctionAddress (m_llvm_function_name);
2808 
2809  if (void_fn == 0)
2810  {
2811  llvm_function->eraseFromParent ();
2812  llvm_function = nullptr;
2813  m_function = nullptr;
2814  }
2815  else
2816  {
2817  m_function = reinterpret_cast<jited_function> (void_fn);
2818  }
2819  }
2820  }
2821 
2822  octave_value
2823  jit_info::find (const vmap& extra_vars, const std::string& vname) const
2824  {
2825  vmap::const_iterator iter = extra_vars.find (vname);
2826 
2827  if (iter == extra_vars.end ())
2828  {
2829  symbol_scope scope = __require_current_scope__ ("jit_convert::find");
2830 
2831  return scope.varval (vname);
2832  }
2833  else
2834  return *iter->second;
2835  }
2836 }
2837 
2838 #endif
2839 
2840 DEFUN (jit_failcnt, args, nargout,
2841  doc: /* -*- texinfo -*-
2842 @deftypefn {} {@var{val} =} jit_failcnt ()
2843 @deftypefnx {} {@var{old_val} =} jit_failcnt (@var{new_val})
2844 @deftypefnx {} {} jit_failcnt (@var{new_val}, "local")
2845 Query or set the internal variable that counts the number of JIT fail
2846 exceptions for Octave's JIT compiler.
2847 
2848 When called from inside a function with the @qcode{"local"} option, the
2849 variable is changed locally for the function and any subroutines it calls.
2850 The original variable value is restored when exiting the function.
2851 @seealso{jit_enable, jit_startcnt, debug_jit}
2852 @end deftypefn */)
2853 {
2854 #if defined (HAVE_LLVM)
2855  return SET_INTERNAL_VARIABLE (jit_failcnt);
2856 #else
2857  octave_unused_parameter (args);
2858  octave_unused_parameter (nargout);
2859  warn_disabled_feature ("jit_failcnt", "JIT compiling");
2860  return ovl ();
2861 #endif
2862 }
2863 
2864 DEFUN (debug_jit, args, nargout,
2865  doc: /* -*- texinfo -*-
2866 @deftypefn {} {@var{val} =} debug_jit ()
2867 @deftypefnx {} {@var{old_val} =} debug_jit (@var{new_val})
2868 @deftypefnx {} {} debug_jit (@var{new_val}, "local")
2869 Query or set the internal variable that determines whether
2870 debugging/tracing is enabled for Octave's JIT compiler.
2871 
2872 When called from inside a function with the @qcode{"local"} option, the
2873 variable is changed locally for the function and any subroutines it calls.
2874 The original variable value is restored when exiting the function.
2875 @seealso{jit_enable, jit_startcnt}
2876 @end deftypefn */)
2877 {
2878 #if defined (HAVE_LLVM)
2879  return SET_INTERNAL_VARIABLE (debug_jit);
2880 #else
2881  octave_unused_parameter (args);
2882  octave_unused_parameter (nargout);
2883  warn_disabled_feature ("debug_jit", "JIT");
2884  return ovl ();
2885 #endif
2886 }
2887 
2888 DEFUN (jit_enable, args, nargout,
2889  doc: /* -*- texinfo -*-
2890 @deftypefn {} {@var{val} =} jit_enable ()
2891 @deftypefnx {} {@var{old_val} =} jit_enable (@var{new_val})
2892 @deftypefnx {} {} jit_enable (@var{new_val}, "local")
2893 Query or set the internal variable that enables Octave's JIT compiler.
2894 
2895 When called from inside a function with the @qcode{"local"} option, the
2896 variable is changed locally for the function and any subroutines it calls.
2897 The original variable value is restored when exiting the function.
2898 @seealso{jit_startcnt, debug_jit}
2899 @end deftypefn */)
2900 {
2901 #if defined (HAVE_LLVM)
2902  return SET_INTERNAL_VARIABLE (jit_enable);
2903 #else
2904  octave_unused_parameter (args);
2905  octave_unused_parameter (nargout);
2906  warn_disabled_feature ("jit_enable", "JIT");
2907  return ovl ();
2908 #endif
2909 }
2910 
2911 DEFUN (jit_startcnt, args, nargout,
2912  doc: /* -*- texinfo -*-
2913 @deftypefn {} {@var{val} =} jit_startcnt ()
2914 @deftypefnx {} {@var{old_val} =} jit_startcnt (@var{new_val})
2915 @deftypefnx {} {} jit_startcnt (@var{new_val}, "local")
2916 Query or set the internal variable that determines whether JIT compilation
2917 will take place for a specific loop.
2918 
2919 Because compilation is a costly operation it does not make sense to employ
2920 JIT when the loop count is low. By default only loops with greater than
2921 1000 iterations will be accelerated.
2922 
2923 When called from inside a function with the @qcode{"local"} option, the
2924 variable is changed locally for the function and any subroutines it calls.
2925 The original variable value is restored when exiting the function.
2926 @seealso{jit_enable, jit_failcnt, debug_jit}
2927 @end deftypefn */)
2928 {
2929 #if defined (HAVE_LLVM)
2930  return SET_INTERNAL_VARIABLE_WITH_LIMITS (jit_startcnt, 1,
2932 #else
2933  octave_unused_parameter (args);
2934  octave_unused_parameter (nargout);
2935  warn_disabled_feature ("jit_startcnt", "JIT");
2936  return ovl ();
2937 #endif
2938 }
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
Definition: Range.h:40
octave_idx_type numel(void) const
Definition: Range.h:87
void add_method(T *obj, void(T::*method)(Params...), Args &&... args)
elt_type & front(void)
Definition: base-list.h:79
size_t size(void) const
Definition: base-list.h:52
iterator begin(void)
Definition: base-list.h:65
elt_type & back(void)
Definition: base-list.h:80
iterator end(void)
Definition: base-list.h:68
bool have_breakpoints(void)
Definition: bp-table.h:100
jit_variable * dest(void) const
Definition: jit-ir.h:907
jit_value * src(void) const
Definition: jit-ir.h:947
void mark_artificial(void)
Definition: jit-ir.h:959
jit_value * overwrite(void) const
Definition: jit-ir.h:942
bool artificial(void) const
Definition: jit-ir.h:957
iterator erase(iterator iter)
Definition: jit-ir.h:156
jit_block * front(void) const
Definition: jit-ir.h:158
void label(void)
Definition: jit-ir.cc:95
iterator end(void)
Definition: jit-ir.h:152
void push_back(jit_block *b)
Definition: jit-ir.cc:126
jit_block * back(void) const
Definition: jit-ir.h:146
iterator begin(void)
Definition: jit-ir.h:148
std::list< jit_block * >::iterator iterator
Definition: jit-ir.h:143
std::ostream & print(std::ostream &os, const std::string &header) const
Definition: jit-ir.cc:105
llvm::BasicBlock * to_llvm(void) const
Definition: jit-ir.cc:394
T * append(T *instr)
Definition: jit-ir.h:608
void create_dom_tree(void)
Definition: jit-ir.h:696
static const size_t NO_ID
Definition: jit-ir.h:574
jit_instruction * back(void)
Definition: jit-ir.h:764
size_t id(void) const
Definition: jit-ir.h:660
size_t dom_successor_count(void) const
Definition: jit-ir.h:706
iterator remove(iterator iter)
Definition: jit-ir.h:628
jit_instruction * insert_after(iterator loc, jit_instruction *instr)
Definition: jit-ir.cc:355
size_t successor_count(void) const
Definition: jit-ir.cc:387
iterator end(void)
Definition: jit-ir.h:649
jit_block * maybe_split(jit_factory &factory, jit_block_list &blocks, jit_block *asuccessor)
Definition: jit-ir.cc:538
jit_block * successor(size_t i) const
Definition: jit-ir.cc:380
bool visited(size_t avisit_count)
Definition: jit-ir.h:751
bool alive(void) const
Definition: jit-ir.h:591
std::set< jit_block * > df_set
Definition: jit-ir.h:571
iterator begin(void)
Definition: jit-ir.h:645
jit_instruction * prepend(jit_instruction *instr)
Definition: jit-ir.cc:315
jit_terminator * terminator(void) const
Definition: jit-ir.cc:364
df_iterator df_begin(void) const
Definition: jit-ir.h:665
void compute_idom(jit_block &entry_block)
Definition: jit-ir.h:681
const std::string & name(void) const
Definition: jit-ir.h:601
void pop_all(void)
Definition: jit-ir.cc:506
size_t use_count(void) const
Definition: jit-ir.h:588
jit_instruction * front(void)
Definition: jit-ir.h:762
jit_block * dom_successor(size_t idx) const
Definition: jit-ir.h:701
df_iterator df_end(void) const
Definition: jit-ir.h:667
void mark_alive(void)
Definition: jit-ir.h:593
jit_instruction * insert_before(iterator loc, jit_instruction *instr)
Definition: jit-ir.cc:347
void compute_df(void)
Definition: jit-ir.h:691
const jit_function & overload(void) const
Definition: jit-ir.h:1211
llvm::Value * cond_llvm(void) const
Definition: jit-ir.h:1149
PASS_T value(void) const
Definition: jit-ir.h:536
llvm::Function * convert_loop(const jit_module &module, const jit_block_list &blocks, const std::list< jit_value * > &constants, const std::string &llvm_function_name)
Definition: pt-jit.cc:1320
jit_function convert_function(const jit_module &module, const jit_block_list &blocks, const std::list< jit_value * > &constants, octave_user_function &fcn, const std::vector< jit_type * > &args)
Definition: pt-jit.cc:1378
llvm::Function * m_function
Definition: pt-jit.h:291
std::map< std::string, llvm::Value * > m_arguments
Definition: pt-jit.h:284
void finish_phi(jit_phi *phi)
Definition: pt-jit.cc:1463
void convert(const jit_block_list &blocks, const std::list< jit_value * > &constants)
Definition: pt-jit.cc:1424
const std::vector< std::pair< std::string, bool > > & get_arguments(void) const
Definition: pt-jit.h:266
llvm::BasicBlock * m_prelude
Definition: pt-jit.h:292
jit_function m_creating
Definition: pt-jit.h:289
std::vector< std::pair< std::string, bool > > m_argument_vec
Definition: pt-jit.h:281
virtual void visit(jit_block &)
Definition: pt-jit.cc:1527
void visit_boolean_expression(tree_boolean_expression &)
Definition: pt-jit.cc:324
void visit_prefix_expression(tree_prefix_expression &)
Definition: pt-jit.cc:761
void visit_octave_user_function_trailer(octave_user_function &)
Definition: pt-jit.cc:548
size_t m_iterator_count
Definition: pt-jit.h:192
void visit_simple_assignment(tree_simple_assignment &)
Definition: pt-jit.cc:779
void visit_octave_user_function(octave_user_function &)
Definition: pt-jit.cc:536
symbol_scope m_scope
Definition: pt-jit.h:173
void visit_complex_for_command(tree_complex_for_command &)
Definition: pt-jit.cc:524
std::string next_name(const char *prefix, size_t &count, bool inc)
Definition: pt-jit.cc:1188
bool m_converting_function
Definition: pt-jit.h:170
std::string next_for_bounds(bool inc=true)
Definition: pt-jit.h:220
void visit_octave_user_function_header(octave_user_function &)
Definition: pt-jit.cc:542
void visit_statement_list(tree_statement_list &)
void visit_parameter_list(tree_parameter_list &)
Definition: pt-jit.cc:737
block_list m_continues
Definition: pt-jit.h:243
void visit_multi_assignment(tree_multi_assignment &)
Definition: pt-jit.cc:693
jit_factory & get_factory(void)
Definition: pt-jit.h:75
void visit_switch_command(tree_switch_command &)
Definition: pt-jit.cc:851
void visit_no_op_command(tree_no_op_command &)
Definition: pt-jit.cc:699
variable_map m_vmap
Definition: pt-jit.h:196
void visit_unwind_protect_command(tree_unwind_protect_command &)
Definition: pt-jit.cc:965
jit_factory m_factory
Definition: pt-jit.h:175
jit_call * create_checked_impl(jit_call *ret)
Definition: pt-jit.cc:1113
jit_block_list & get_blocks(void)
Definition: pt-jit.h:71
void visit_break_command(tree_break_command &)
Definition: pt-jit.cc:370
void visit_do_until_command(tree_do_until_command &)
Definition: pt-jit.cc:1033
void visit_switch_case(tree_switch_case &)
Definition: pt-jit.cc:839
jit_instruction * resolve(tree_index_expression &exp, jit_value *extra_arg=nullptr, bool lhs=false)
Definition: pt-jit.cc:1198
void visit_octave_user_script(octave_user_script &)
Definition: pt-jit.cc:530
size_t m_short_count
Definition: pt-jit.h:194
jit_block_list m_blocks
Definition: pt-jit.h:188
jit_value * do_assign(tree_expression *exp, jit_value *rhs, bool artificial=false)
Definition: pt-jit.cc:1256
jit_block * m_entry_block
Definition: pt-jit.h:180
jit_block * m_final_block
Definition: pt-jit.h:182
void visit_matrix(tree_matrix &)
Definition: pt-jit.cc:681
jit_variable * create_variable(const std::string &vname, jit_type *type, bool isarg=true)
Definition: pt-jit.cc:1165
void visit_argument_list(tree_argument_list &)
Definition: pt-jit.cc:305
void visit_if_command_list(tree_if_command_list &)
Definition: pt-jit.cc:584
void visit_binary_expression(tree_binary_expression &)
Definition: pt-jit.cc:311
jit_value * visit(tree *tee)
Definition: pt-jit.h:237
block_list m_breaks
Definition: pt-jit.h:242
const variable_map & get_variable_map(void) const
Definition: pt-jit.h:79
void visit_return_command(tree_return_command &)
Definition: pt-jit.cc:773
void visit_decl_command(tree_decl_command &)
Definition: pt-jit.cc:402
void visit_fcn_handle(tree_fcn_handle &)
Definition: pt-jit.cc:731
void visit_if_clause(tree_if_clause &)
Definition: pt-jit.cc:578
jit_variable * get_variable(const std::string &vname)
Definition: pt-jit.cc:1137
void visit_identifier(tree_identifier &)
Definition: pt-jit.cc:560
void visit_statement(tree_statement &)
Definition: pt-jit.cc:800
void visit_constant(tree_constant &)
Definition: pt-jit.cc:705
jit_convert(tree &tee, jit_type *for_bounds=nullptr)
Definition: pt-jit.cc:164
jit_block * m_block
Definition: pt-jit.h:184
void finish_breaks(jit_block *dest, const block_list &lst)
Definition: pt-jit.cc:1309
std::string next_shortcircut_result(bool inc=true)
Definition: pt-jit.h:223
void visit_anon_fcn_handle(tree_anon_fcn_handle &)
Definition: pt-jit.cc:299
std::pair< jit_type *, std::string > type_bound
Definition: pt-jit.h:56
std::vector< jit_magic_end::context > m_end_context
Definition: pt-jit.h:190
void visit_decl_init_list(tree_decl_init_list &)
Definition: pt-jit.cc:414
size_t m_for_bounds_count
Definition: pt-jit.h:193
std::string next_iterator(bool inc=true)
Definition: pt-jit.h:217
void visit_switch_case_list(tree_switch_case_list &)
Definition: pt-jit.cc:845
void visit_decl_elt(tree_decl_elt &)
Definition: pt-jit.cc:408
void visit_continue_command(tree_continue_command &)
Definition: pt-jit.cc:395
void visit_index_expression(tree_index_expression &)
Definition: pt-jit.cc:675
void visit_cell(tree_cell &)
Definition: pt-jit.cc:687
type_bound_vector m_bounds
Definition: pt-jit.h:168
std::list< jit_block * > block_list
Definition: pt-jit.h:241
void visit_while_command(tree_while_command &)
Definition: pt-jit.cc:971
void initialize(const symbol_scope &s)
Definition: pt-jit.cc:1097
void visit_function_def(tree_function_def &)
Definition: pt-jit.cc:554
jit_call * create_checked(const Args &... args)
Definition: pt-jit.h:65
void visit_colon_expression(tree_colon_expression &)
Definition: pt-jit.cc:377
void visit_try_catch_command(tree_try_catch_command &)
Definition: pt-jit.cc:959
void visit_postfix_expression(tree_postfix_expression &)
Definition: pt-jit.cc:743
const type_bound_vector & get_bounds(void) const
Definition: pt-jit.h:73
jit_value * m_result
Definition: pt-jit.h:178
void visit_simple_for_command(tree_simple_for_command &)
Definition: pt-jit.cc:420
jit_variable * find_variable(const std::string &vname) const
Definition: pt-jit.cc:1129
variable check_variable(void) const
Definition: jit-ir.h:1268
const std::string & name(void) const
Definition: jit-ir.h:1353
const jit_function & overload(void) const
Definition: jit-ir.h:1358
const value_list & constants(void) const
Definition: jit-ir.h:115
T * create(const Args &... args)
Definition: jit-ir.h:118
bool known(void) const
Definition: jit-util.h:110
jit_function_info(octave_user_function &fcn, const octave_value_list &ov_args)
Definition: pt-jit.cc:2482
bool match(const octave_value_list &ov_args) const
Definition: pt-jit.cc:2644
jited_function m_function
Definition: pt-jit.h:637
std::string m_llvm_function_name
Definition: pt-jit.h:636
bool execute(const octave_value_list &ov_args, octave_value_list &retval) const
Definition: pt-jit.cc:2617
octave_base_value *(* jited_function)(octave_base_value **)
Definition: pt-jit.h:633
std::vector< jit_type * > m_argument_types
Definition: pt-jit.h:639
bool valid(void) const
Definition: jit-typeinfo.h:262
llvm::Value * call(llvm::IRBuilderD &builder, const arg_vec &in_args=arg_vec()) const
jit_type * result(void) const
Definition: jit-typeinfo.h:327
llvm::BasicBlock * new_block(const std::string &aname="body", llvm::BasicBlock *insert_before=nullptr)
llvm::Value * argument(llvm::IRBuilderD &builder, size_t idx) const
llvm::Function * to_llvm(void) const
Definition: jit-typeinfo.h:318
void do_return(llvm::IRBuilderD &builder, llvm::Value *rval=nullptr, bool verify=true)
std::list< jit_instruction * > m_worklist
Definition: pt-jit.h:332
void append_users(jit_value *v)
Definition: pt-jit.cc:1721
jit_block_list & get_blocks(void) const
Definition: pt-jit.h:321
void do_construct_ssa(jit_block &block, size_t avisit_count)
Definition: pt-jit.cc:1792
void push_worklist(jit_instruction *instr)
Definition: pt-jit.cc:1852
void release_dead_phi(jit_block &ablock)
Definition: pt-jit.cc:1912
jit_block_list & m_blocks
Definition: pt-jit.h:329
jit_infer(jit_factory &afactory, jit_block_list &ablocks, const variable_map &avmap)
Definition: pt-jit.cc:1679
void release_temp(jit_block &ablock, std::set< jit_value * > &temp)
Definition: pt-jit.cc:1948
void place_releases(void)
Definition: pt-jit.cc:1837
jit_convert::variable_map variable_map
Definition: pt-jit.h:316
void construct_ssa(void)
Definition: pt-jit.cc:1747
void infer(void)
Definition: pt-jit.cc:1684
jit_block & entry_block(void)
Definition: pt-jit.h:342
void remove_dead()
Definition: pt-jit.cc:1862
void append_users_term(jit_terminator *term)
Definition: pt-jit.cc:1728
const variable_map & m_vmap
Definition: pt-jit.h:331
void simplify_phi(void)
Definition: pt-jit.cc:2001
jit_block & final_block(void)
Definition: pt-jit.h:344
jit_factory & m_factory
Definition: pt-jit.h:330
octave_value find(const vmap &extra_vars, const std::string &vname) const
Definition: pt-jit.cc:2823
void compile(tree &tee, jit_type *for_bounds=0)
Definition: pt-jit.cc:2743
void(* jited_function)(octave_base_value **)
Definition: pt-jit.h:603
type_bound_vector m_bounds
Definition: pt-jit.h:614
bool execute(const vmap &extra_vars=vmap()) const
Definition: pt-jit.cc:2685
std::vector< std::pair< std::string, bool > > m_arguments
Definition: pt-jit.h:613
jited_function m_function
Definition: pt-jit.h:611
std::map< std::string, const octave_value * > vmap
Definition: pt-jit.h:587
bool match(const vmap &extra_vars=vmap()) const
Definition: pt-jit.cc:2723
std::string m_llvm_function_name
Definition: pt-jit.h:610
jit_info(tree &tee)
Definition: pt-jit.cc:2662
llvm::Value * argument_llvm(size_t i) const
Definition: jit-ir.h:374
const std::vector< jit_use > & arguments(void) const
Definition: jit-ir.h:434
virtual void push_variable(void)
Definition: jit-ir.h:440
void stash_argument(size_t i, jit_value *arg)
Definition: jit-ir.h:399
size_t argument_count(void) const
Definition: jit-ir.h:418
jit_block * parent(void) const
Definition: jit-ir.h:455
virtual bool infer(void)
Definition: jit-ir.h:449
jit_value * argument(size_t i) const
Definition: jit-ir.h:369
static void reset_ids(void)
Definition: jit-ir.h:364
virtual void construct_ssa(void)
Definition: jit-ir.h:444
NODE_T * first_use(void) const
Definition: jit-util.h:145
size_t use_count(void) const
Definition: jit-util.h:147
NODE_T * next(void) const
Definition: jit-util.h:196
jit_const_index * m_index
Definition: jit-ir.h:1316
jit_const_index * m_count
Definition: jit-ir.h:1317
const jit_function & overload() const
Definition: jit-ir.cc:841
context resolve_context(void) const
Definition: jit-ir.cc:801
void operator=(const jit_memory_manager &)=delete
virtual ~jit_memory_manager()
Definition: pt-jit.cc:2050
virtual void * getPointerToNamedFunction(const std::string &name, bool abort_on_failure)
Definition: pt-jit.cc:2065
virtual uint64_t getSymbolAddress(const std::string &name)
Definition: pt-jit.cc:2082
jit_memory_manager(const jit_memory_manager &)=delete
llvm::Function * create_llvm_function(llvm::FunctionType *ftype, const llvm::Twine &name) const
Definition: pt-jit.cc:2359
llvm::ExecutionEngine * m_engine
Definition: pt-jit.h:577
void do_add_global_mapping(const llvm::GlobalValue *gv, void *p) const
Definition: pt-jit.cc:2390
jit_module(const std::string &module_name=tree_jit::generate_unique_module_name())
Definition: pt-jit.cc:2328
void optimize(llvm::Function *fn) const
Definition: pt-jit.cc:2404
uint64_t getFunctionAddress(const std::string &name) const
Definition: pt-jit.cc:2398
llvm::Module * m_module
Definition: pt-jit.h:576
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
llvm::Function * get_intrinsic_declaration(size_t id, std::vector< llvm::Type * > types) const
Definition: pt-jit.cc:2372
llvm::BasicBlock * incoming_llvm(size_t i) const
Definition: jit-ir.h:1016
void add_incoming(jit_block *from, jit_value *value)
Definition: jit-ir.h:1004
llvm::PHINode * to_llvm(void) const
Definition: jit-ir.cc:667
bool prune(void)
Definition: jit-ir.cc:602
jit_block * incoming(size_t i) const
Definition: jit-ir.h:1011
jit_value * result(void) const
Definition: jit-ir.h:1438
jit_type * result_type(void) const
Definition: jit-ir.h:1443
const jit_function & overload(void) const
Definition: jit-ir.h:1387
const std::string & name(void) const
Definition: jit-ir.h:1382
jit_value * result(void) const
Definition: jit-ir.h:1392
llvm::BasicBlock * successor_llvm(size_t idx=0) const
Definition: jit-ir.h:1074
bool alive(const jit_block *asuccessor) const
Definition: jit-ir.h:1092
size_t successor_count(void) const
Definition: jit-ir.h:1101
jit_block * successor(size_t idx=0) const
Definition: jit-ir.h:1069
virtual bool infer(void)
Definition: jit-ir.cc:685
llvm::Type * to_llvm(void) const
Definition: jit-typeinfo.h:160
static const jit_operation & paren_subsasgn(void)
Definition: jit-typeinfo.h:620
static llvm::Value * insert_interrupt_check(llvm::IRBuilderD &bld)
Definition: jit-typeinfo.h:718
static llvm::Type * get_scalar_llvm(void)
Definition: jit-typeinfo.h:567
static llvm::Value * insert_error_check(llvm::IRBuilderD &bld)
Definition: jit-typeinfo.h:713
static llvm::Value * create_complex(llvm::Value *real, llvm::Value *imag)
Definition: jit-typeinfo.h:739
static jit_type * get_scalar(void)
Definition: jit-typeinfo.h:548
static const jit_function & get_release(jit_type *type)
Definition: jit-typeinfo.h:663
static const jit_operation & destroy(void)
Definition: jit-typeinfo.h:668
static llvm::Type * get_index_llvm(void)
Definition: jit-typeinfo.h:569
static const jit_operation & cast(jit_type *result)
Definition: jit-typeinfo.h:703
static jit_type * get_any_ptr(void)
Definition: jit-typeinfo.h:552
static jit_type * get_any(void)
Definition: jit-typeinfo.h:544
static const jit_operation & logically_true(void)
Definition: jit-typeinfo.h:698
static jit_type * get_complex(void)
Definition: jit-typeinfo.h:562
static const jit_operation & for_check(void)
Definition: jit-typeinfo.h:683
static jit_type * get_range(void)
Definition: jit-typeinfo.h:554
static const jit_operation & unary_op(int op)
Definition: jit-typeinfo.h:643
static const jit_operation & for_index(void)
Definition: jit-typeinfo.h:688
static jit_type * type_of(const octave_value &ov)
Definition: jit-typeinfo.h:632
static const jit_operation & release(void)
Definition: jit-typeinfo.h:658
static const jit_operation & grab(void)
Definition: jit-typeinfo.h:648
static const jit_operation & for_init(void)
Definition: jit-typeinfo.h:678
static const jit_operation & paren_subsref(void)
Definition: jit-typeinfo.h:619
static const jit_operation & binary_op(int op)
Definition: jit-typeinfo.h:638
static const jit_operation & make_range(void)
Definition: jit-typeinfo.h:693
static const jit_operation & create_undef(void)
Definition: jit-typeinfo.h:734
static const jit_operation & print_value(void)
Definition: jit-typeinfo.h:673
jit_instruction * user(void) const
Definition: jit-ir.h:310
void stash_llvm(llvm::Value *compiled)
Definition: jit-ir.h:259
virtual bool needs_release(void) const
Definition: jit-ir.h:239
virtual void replace_with(jit_value *m_value)
Definition: jit-ir.cc:171
bool in_worklist(void) const
Definition: jit-ir.h:194
jit_type * type(void) const
Definition: jit-ir.h:211
jit_block * first_use_block(void)
Definition: jit-ir.cc:156
void stash_in_worklist(bool ain_worklist)
Definition: jit-ir.h:199
llvm::Value * to_llvm(void) const
Definition: jit-ir.h:253
llvm::Type * type_llvm(void) const
Definition: jit-ir.h:213
bool has_top(void) const
Definition: jit-ir.h:834
const std::string & name(void) const
Definition: jit-ir.h:830
jit_value * top(void) const
Definition: jit-ir.h:839
symbol_record find_symbol(const std::string &name)
Definition: symscope.h:482
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
tree_expression * lhs(void)
Definition: pt-binop.h:96
octave_value::binary_op op_type(void) const
Definition: pt-binop.h:94
tree_expression * rhs(void)
Definition: pt-binop.h:97
type op_type(void) const
Definition: pt-binop.h:176
tree_expression * increment(void)
Definition: pt-colon.h:88
tree_expression * limit(void)
Definition: pt-colon.h:86
tree_expression * base(void)
Definition: pt-colon.h:84
octave_value value(void)
Definition: pt-const.h:86
std::string name(void) const
Definition: pt-decl.h:90
virtual bool is_identifier(void) const
Definition: pt-exp.h:70
virtual std::string name(void) const
Definition: pt-exp.h:103
virtual bool is_assignment_expression(void) const
Definition: pt-exp.h:74
bool print_result(void) const
Definition: pt-exp.h:99
std::string name(void) const
Definition: pt-id.h:73
tree_expression * condition(void)
Definition: pt-select.h:69
bool is_else_clause(void)
Definition: pt-select.h:67
tree_statement_list * commands(void)
Definition: pt-select.h:71
std::string type_tags(void)
Definition: pt-idx.h:87
std::list< tree_argument_list * > arg_lists(void)
Definition: pt-idx.h:85
tree_expression * expression(void)
Definition: pt-idx.h:83
static tree_jit & instance(void)
Definition: pt-jit.cc:2119
static int next_module_number
Definition: pt-jit.h:480
void * do_getPointerToNamedFunction(const std::string &Name) const
Definition: pt-jit.cc:2163
uint64_t do_getSymbolAddress(const std::string &name) const
Definition: pt-jit.cc:2179
void do_register_jit_module(jit_module *jm)
Definition: pt-jit.cc:2151
static llvm::LLVMContext llvm_context
Definition: pt-jit.h:389
void do_unregister_jit_module(jit_module *jm)
Definition: pt-jit.cc:2157
static void * getPointerToNamedFunction(const std::string &name)
Definition: pt-jit.h:439
static bool initialized
Definition: pt-jit.h:382
size_t trip_count(const octave_value &bounds) const
Definition: pt-jit.cc:2313
std::list< jit_module * > jm_list
Definition: pt-jit.h:430
static uint64_t getSymbolAddress(const std::string &name)
Definition: pt-jit.h:442
bool enabled(void)
Definition: pt-jit.cc:2301
static jit::ModuleOwner open_new_module(const std::string &module_name=generate_unique_module_name())
Definition: pt-jit.cc:2216
static int next_function_number
Definition: pt-jit.h:479
static void unregister_jit_module(jit_module *jm)
Definition: pt-jit.h:424
static void register_jit_module(jit_module *jm)
Definition: pt-jit.h:421
static int next_forloop_number
Definition: pt-jit.h:478
bool do_initialize(void)
Definition: pt-jit.cc:2195
llvm::TargetMachine * target_machine
Definition: pt-jit.h:400
static jit::EngineOwner create_new_engine(jit::ModuleOwner module_owner)
Definition: pt-jit.cc:2131
jit::ModuleOwner do_open_new_module(const std::string &module_name) const
Definition: pt-jit.cc:2222
bool do_execute(tree_simple_for_command &cmd, const octave_value &bounds)
Definition: pt-jit.cc:2237
bool takes_varargs(void) const
Definition: pt-misc.h:85
void visit_octave_user_function_trailer(octave_user_function &)
Definition: pt-pr-code.cc:363
void visit_statement_list(tree_statement_list &)
Definition: pt-pr-code.cc:861
void visit_octave_user_function_header(octave_user_function &)
Definition: pt-pr-code.cc:328
tree_expression * right_hand_side(void)
Definition: pt-assign.h:79
octave_value::assign_op op_type(void) const
Definition: pt-assign.h:95
tree_expression * left_hand_side(void)
Definition: pt-assign.h:77
tree_expression * control_expr(void)
Definition: pt-loop.h:210
jit_info * get_info(void) const
Definition: pt-loop.h:227
void stash_info(jit_info *jinfo)
Definition: pt-loop.h:232
tree_expression * left_hand_side(void)
Definition: pt-loop.h:208
tree_statement_list * body(void)
Definition: pt-loop.h:214
void accept(tree_walker &tw)
Definition: pt-stmt.h:199
tree_expression * expression(void)
Definition: pt-stmt.h:101
tree_command * command(void)
Definition: pt-stmt.h:99
tree_statement_list * commands(void)
Definition: pt-select.h:196
tree_expression * case_label(void)
Definition: pt-select.h:194
bool is_default_case(void)
Definition: pt-select.h:192
tree_switch_case_list * case_list(void)
Definition: pt-select.h:271
tree_expression * switch_value(void)
Definition: pt-select.h:269
tree_expression * operand(void)
Definition: pt-unop.h:72
octave_value::unary_op op_type(void) const
Definition: pt-unop.h:76
tree_statement_list * body(void)
Definition: pt-loop.h:90
jit_info * get_info(void) const
Definition: pt-loop.h:103
void stash_info(jit_info *jinfo)
Definition: pt-loop.h:105
tree_expression * condition(void)
Definition: pt-loop.h:88
std::string str_print_code(void)
Definition: pt.cc:46
virtual void accept(tree_walker &tw)=0
void grab(void)
Definition: ov-base.h:817
std::string name(void) const
Definition: ov-fcn.h:214
octave::tree_statement_list * body(void)
Definition: ov-usr-fcn.h:123
octave::symbol_scope scope(void)
Definition: ov-usr-fcn.h:98
octave::jit_function_info * get_info(void)
Definition: ov-usr-fcn.h:411
octave::tree_expression * special_expr(void)
Definition: ov-usr-fcn.cc:506
bool is_special_expr(void) const
Definition: ov-usr-fcn.h:338
octave::tree_parameter_list * return_list(void)
Definition: ov-usr-fcn.h:396
octave::tree_parameter_list * parameter_list(void)
Definition: ov-usr-fcn.h:394
void stash_info(octave::jit_function_info *info)
Definition: ov-usr-fcn.h:413
octave_idx_type length(void) const
Definition: ovl.h:113
unary_op
Definition: ov.h:83
@ 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
Range range_value(void) const
Definition: ov.h:938
octave_base_value * internal_rep(void) const
Definition: ov.h:1321
assign_op
Definition: ov.h:138
@ op_asn_eq
Definition: ov.h:139
binary_op
Definition: ov.h:96
@ op_add
Definition: ov.h:97
@ op_eq
Definition: ov.h:105
bool is_range(void) const
Definition: ov.h:602
static binary_op assign_op_to_binary_op(assign_op)
Definition: ov.cc:398
bool is_undefined(void) const
Definition: ov.h:554
double double_value(bool frc_str_conv=false) const
Definition: ov.h:794
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:968
#define panic_impossible()
Definition: error.h:380
void warn_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:318
QString name
T octave_idx_type m
Definition: mx-inlines.cc:773
std::string release(void)
Definition: defaults.cc:143
std::unique_ptr< llvm::ExecutionEngine > EngineOwner
Definition: pt-jit.h:47
llvm::FunctionPassManager FunctionPassManager
Definition: pt-jit.cc:147
std::unique_ptr< llvm::Module > ModuleOwner
Definition: pt-jit.h:46
llvm::PassManager PassManager
Definition: pt-jit.cc:146
std::string tail(const std::string &path)
Definition: file-ops.cc:370
jit_const< double, jit_typeinfo::get_scalar > jit_const_scalar
Definition: jit-ir.h:90
jit_const< octave_idx_type, jit_typeinfo::get_index > jit_const_index
Definition: jit-ir.h:92
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:80
bp_table & __get_bp_table__(const std::string &who)
static uint32_t * next
Definition: randmtzig.cc:189
jit_const< Complex, jit_typeinfo::get_complex > jit_const_complex
Definition: jit-ir.h:91
bool Vdebug_on_interrupt
Definition: sighandlers.cc:71
symbol_scope __get_current_scope__(const std::string &who)
symbol_table & __get_symbol_table__(const std::string &who)
static llvm::IRBuilder builder(tree_jit::llvm_context)
symbol_scope __require_current_scope__(const std::string &who)
jit_const< jit_range, jit_typeinfo::get_range, const jit_range & > jit_const_range
Definition: jit-ir.h:98
std::complex< double > Complex
Definition: oct-cmplx.h:33
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
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
static int Vjit_startcnt
Definition: pt-jit.cc:134
static bool Vjit_enable
Definition: pt-jit.cc:132
static bool Vdebug_jit
Definition: pt-jit.cc:130
static int Vjit_failcnt
Definition: pt-jit.cc:136
#define SET_INTERNAL_VARIABLE_WITH_LIMITS(NM, MINVAL, MAXVAL)
Definition: variables.h:109
#define SET_INTERNAL_VARIABLE(NM)
Definition: variables.h:103