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