GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
jit-ir.h
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2012-2017 Max Brister
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // Author: Max Brister <max@2bass.com>
24 
25 #if ! defined (octave_jit_ir_h)
26 #define octave_jit_ir_h 1
27 
28 #include "octave-config.h"
29 
30 #if defined (HAVE_LLVM)
31 
32 #include <list>
33 #include <stack>
34 #include <set>
35 
36 #include "jit-typeinfo.h"
37 
38 // The low level octave jit ir
39 // this ir is close to llvm, but contains information for doing type inference.
40 // We convert the octave parse tree to this IR directly.
41 
42 #define JIT_VISIT_IR_NOTEMPLATE \
43  JIT_METH(block); \
44  JIT_METH(branch); \
45  JIT_METH(cond_branch); \
46  JIT_METH(call); \
47  JIT_METH(extract_argument); \
48  JIT_METH(store_argument); \
49  JIT_METH(return); \
50  JIT_METH(phi); \
51  JIT_METH(variable); \
52  JIT_METH(error_check); \
53  JIT_METH(assign) \
54  JIT_METH(argument) \
55  JIT_METH(magic_end)
56 
57 #define JIT_VISIT_IR_CONST \
58  JIT_METH(const_bool); \
59  JIT_METH(const_scalar); \
60  JIT_METH(const_complex); \
61  JIT_METH(const_index); \
62  JIT_METH(const_string); \
63  JIT_METH(const_range)
64 
65 #define JIT_VISIT_IR_CLASSES \
66  JIT_VISIT_IR_NOTEMPLATE \
67  JIT_VISIT_IR_CONST
68 
69 // forward declare all ir classes
70 #define JIT_METH(cname) \
71  class jit_ ## cname;
72 
74 
75 #undef JIT_METH
76 
77 // ABCs which aren't included in JIT_VISIT_IR_ALL
78 class jit_instruction;
79 class jit_terminator;
80 
81 template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T = T,
82  bool QUOTE=false>
83 class jit_const;
84 
89 
94 
95 class jit_ir_walker;
96 class jit_use;
97 
98 // Creates and tracks memory for jit_value and subclasses.
99 // Memory managment is simple, all values that are created live as long as the
100 // factory.
101 class
103 {
104  typedef std::list<jit_value *> value_list;
105 
106 public:
107 
108  ~jit_factory (void);
109 
110  const value_list& constants (void) const { return mconstants; }
111 
112  template <typename T>
113  T *create (void)
114  {
115  T *ret = new T ();
116  track_value (ret);
117  return ret;
118  }
119 
120 #define DECL_ARG(n) const ARG ## n& arg ## n
121 
122 #define JIT_CREATE(N) \
123  template <typename T, OCT_MAKE_DECL_LIST (typename, ARG, N)> \
124  T *create (OCT_MAKE_LIST (DECL_ARG, N)) \
125  { \
126  T *ret = new T (OCT_MAKE_ARG_LIST (arg, N)); \
127  track_value (ret); \
128  return ret; \
129  }
130 
132  JIT_CREATE (2)
133  JIT_CREATE (3)
134  JIT_CREATE (4)
135 
136 #undef JIT_CREATE
137 #undef DECL_ARG
139 private:
141  void track_value (jit_value *v);
142 
143  value_list all_values;
144 
145  value_list mconstants;
146 };
148 // A list of basic blocks (jit_block) which form some body of code.
149 //
150 // We do not directly inherit from std::list because we need to update the
151 // blocks stashed location in push_back and insert.
152 class
154 {
155 public:
156  typedef std::list<jit_block *>::iterator iterator;
157  typedef std::list<jit_block *>::const_iterator const_iterator;
159  jit_block *back (void) const { return mlist.back (); }
161  iterator begin (void) { return mlist.begin (); }
163  const_iterator begin (void) const { return mlist.begin (); }
165  iterator end (void) { return mlist.end (); }
167  const_iterator end (void) const { return mlist.end (); }
168 
169  iterator erase (iterator iter) { return mlist.erase (iter); }
170 
171  jit_block *front (void) const { return mlist.front (); }
172 
173  void insert_after (iterator iter, jit_block *ablock);
174 
175  void insert_after (jit_block *loc, jit_block *ablock);
176 
177  void insert_before (iterator iter, jit_block *ablock);
178 
179  void insert_before (jit_block *loc, jit_block *ablock);
180 
181  void label (void);
182 
183  std::ostream& print (std::ostream& os, const std::string& header) const;
185  std::ostream& print_dom (std::ostream& os) const;
186 
187  void push_back (jit_block *b);
188 private:
189  std::list<jit_block *> mlist;
190 };
191 
192 std::ostream& operator<<(std::ostream& os, const jit_block_list& blocks);
194 class
196 {
197 public:
198  jit_value (void) : llvm_value (0), ty (0), mlast_use (0),
199  min_worklist (false) { }
200 
201  virtual ~jit_value (void);
202 
203  bool in_worklist (void) const
204  {
205  return min_worklist;
206  }
207 
208  void stash_in_worklist (bool ain_worklist)
209  {
210  min_worklist = ain_worklist;
211  }
212 
213  // The block of the first use which is not a jit_error_check
214  // So this is not necessarily first_use ()->parent ().
216 
217  // replace all uses with
218  virtual void replace_with (jit_value *value);
219 
220  jit_type *type (void) const { return ty; }
221 
222  llvm::Type *type_llvm (void) const
223  {
224  return ty ? ty->to_llvm () : 0;
225  }
226 
227  const std::string& type_name (void) const
228  {
229  return ty->name ();
230  }
231 
232  void stash_type (jit_type *new_ty) { ty = new_ty; }
233 
235  {
236  std::stringstream ss;
237  print (ss);
238  return ss.str ();
239  }
240 
241  jit_instruction *last_use (void) const { return mlast_use; }
242 
243  void stash_last_use (jit_instruction *alast_use)
244  {
245  mlast_use = alast_use;
246  }
248  virtual bool needs_release (void) const { return false; }
249 
250  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const = 0;
251 
252  virtual std::ostream& short_print (std::ostream& os) const
253  { return print (os); }
254 
255  virtual void accept (jit_ir_walker& walker) = 0;
256 
257  bool has_llvm (void) const
258  {
259  return llvm_value;
260  }
261 
262  llvm::Value *to_llvm (void) const
263  {
264  assert (llvm_value);
265  return llvm_value;
266  }
267 
268  void stash_llvm (llvm::Value *compiled)
269  {
271  }
272 
273 protected:
274  std::ostream& print_indent (std::ostream& os, size_t indent = 0) const
275  {
276  for (size_t i = 0; i < indent * 8; ++i)
277  os << " ";
278  return os;
279  }
281  llvm::Value *llvm_value;
282 private:
283  jit_type *ty;
285  bool min_worklist;
286 };
287 
288 std::ostream& operator<< (std::ostream& os, const jit_value& value);
289 std::ostream& jit_print (std::ostream& os, jit_value *avalue);
290 
291 class
293 {
294 public:
295  // some compilers don't allow us to use jit_internal_node without template
296  // paremeters
298 
299  jit_use (void) : muser (0), mindex (0) { }
300 
301  // we should really have a move operator, but not until c++11 :(
302  jit_use (const jit_use& use) : muser (0), mindex (0)
303  {
304  *this = use;
305  }
306 
307  jit_use& operator= (const jit_use& use)
308  {
309  stash_value (use.value (), use.user (), use.index ());
310  return *this;
311  }
312 
313  size_t index (void) const { return mindex; }
314 
315  jit_instruction *user (void) const { return muser; }
317  jit_block *user_parent (void) const;
318 
319  std::list<jit_block *> user_parent_location (void) const;
320 
321  void stash_value (jit_value *avalue, jit_instruction *auser = 0,
322  size_t aindex = -1)
323  {
324  PARENT_T::stash_value (avalue);
325  mindex = aindex;
326  muser = auser;
327  }
328 private:
329  jit_instruction *muser;
330  size_t mindex;
331 };
332 
333 class
334 jit_instruction : public jit_value
335 {
336 public:
337  // FIXME: this code could be so much pretier with varadic templates...
338  jit_instruction (void) : mid (next_id ()), mparent (0)
339  { }
340 
341  jit_instruction (size_t nargs) : mid (next_id ()), mparent (0)
342  {
343  already_infered.reserve (nargs);
344  marguments.reserve (nargs);
345  }
346 
347 #define STASH_ARG(i) stash_argument (i, arg ## i);
348 
349 #define JIT_INSTRUCTION_CTOR(N) \
350  jit_instruction (OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \
351  : already_infered (N), marguments (N), mid (next_id ()), mparent (0) \
352  { \
353  OCT_ITERATE_MACRO (STASH_ARG, N); \
354  }
355 
360 
361 #undef STASH_ARG
362 #undef JIT_INSTRUCTION_CTOR
363 
364  jit_instruction (const std::vector<jit_value *>& aarguments)
365  : already_infered (aarguments.size ()), marguments (aarguments.size ()),
366  mid (next_id ()), mparent (0)
367  {
368  for (size_t i = 0; i < aarguments.size (); ++i)
369  stash_argument (i, aarguments[i]);
370  }
371 
372  static void reset_ids (void)
373  {
374  next_id (true);
375  }
376 
377  jit_value *argument (size_t i) const
378  {
379  return marguments[i].value ();
380  }
381 
382  llvm::Value *argument_llvm (size_t i) const
383  {
384  assert (argument (i));
385  return argument (i)->to_llvm ();
386  }
387 
388  jit_type *argument_type (size_t i) const
389  {
390  return argument (i)->type ();
391  }
392 
393  llvm::Type *argument_type_llvm (size_t i) const
394  {
395  assert (argument (i));
396  return argument_type (i)->to_llvm ();
397  }
398 
399  std::ostream& print_argument (std::ostream& os, size_t i) const
400  {
401  if (argument (i))
402  return argument (i)->short_print (os);
403  else
404  return os << "NULL";
405  }
406 
407  void stash_argument (size_t i, jit_value *arg)
408  {
409  marguments[i].stash_value (arg, this, i);
410  }
411 
412  void push_argument (jit_value *arg)
413  {
414  marguments.push_back (jit_use ());
415  stash_argument (marguments.size () - 1, arg);
416  already_infered.push_back (0);
417  }
418 
419  size_t argument_count (void) const
420  {
421  return marguments.size ();
422  }
423 
424  void resize_arguments (size_t acount, jit_value *adefault = 0)
425  {
426  size_t old = marguments.size ();
427  marguments.resize (acount);
428  already_infered.resize (acount);
429 
430  if (adefault)
431  for (size_t i = old; i < acount; ++i)
432  stash_argument (i, adefault);
433  }
434 
435  const std::vector<jit_use>& arguments (void) const { return marguments; }
436 
437  // argument types which have been infered already
438  const std::vector<jit_type *>& argument_types (void) const
439  { return already_infered; }
441  virtual void push_variable (void) { }
442 
443  virtual void pop_variable (void) { }
444 
445  virtual void construct_ssa (void)
446  {
448  }
449 
450  virtual bool infer (void) { return false; }
451 
452  void remove (void);
453 
454  virtual std::ostream& short_print (std::ostream& os) const;
456  jit_block *parent (void) const { return mparent; }
457 
458  std::list<jit_instruction *>::iterator location (void) const
459  {
460  return mlocation;
461  }
463  llvm::BasicBlock *parent_llvm (void) const;
464 
465  void stash_parent (jit_block *aparent,
466  std::list<jit_instruction *>::iterator alocation)
467  {
468  mparent = aparent;
469  mlocation = alocation;
470  }
471 
472  size_t id (void) const { return mid; }
473 protected:
474 
475  // Do SSA replacement on arguments in [start, end)
476  void do_construct_ssa (size_t start, size_t end);
477 
478  std::vector<jit_type *> already_infered;
479 private:
480  static size_t next_id (bool reset = false)
481  {
482  static size_t ret = 0;
483  if (reset)
484  return ret = 0;
485 
486  return ret++;
487  }
488 
489  std::vector<jit_use> marguments;
490 
491  size_t mid;
493  std::list<jit_instruction *>::iterator mlocation;
494 };
496 // defnie accept methods for subclasses
497 #define JIT_VALUE_ACCEPT \
498  virtual void accept (jit_ir_walker& walker);
499 
500 // for use as a dummy argument during conversion to LLVM
501 class
502 jit_argument : public jit_value
503 {
504 public:
505  jit_argument (jit_type *atype, llvm::Value *avalue)
506  {
507  stash_type (atype);
508  stash_llvm (avalue);
509  }
510 
511  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
512  {
513  print_indent (os, indent);
514  return jit_print (os, type ()) << ": DUMMY";
515  }
516 
518 };
519 
520 template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T, bool QUOTE>
521 class
523 {
524 public:
525  typedef PASS_T pass_t;
526 
527  jit_const (PASS_T avalue) : mvalue (avalue)
528  {
529  stash_type (EXTRACT_T ());
530  }
531 
532  PASS_T value (void) const { return mvalue; }
533 
534  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
535  {
536  print_indent (os, indent);
537  jit_print (os, type ()) << ": ";
538  if (QUOTE)
539  os << "\"";
540  os << mvalue;
541  if (QUOTE)
542  os << "\"";
543  return os;
544  }
545 
547 private:
548  T mvalue;
549 };
552 
553 class
556 {
558 public:
559  typedef std::list<jit_instruction *> instruction_list;
560  typedef instruction_list::iterator iterator;
561  typedef instruction_list::const_iterator const_iterator;
562 
563  typedef std::set<jit_block *> df_set;
564  typedef df_set::const_iterator df_iterator;
565 
566  static const size_t NO_ID = static_cast<size_t> (-1);
567 
568  jit_block (const std::string& aname, size_t avisit_count = 0)
569  : mvisit_count (avisit_count), mid (NO_ID), idom (0), mname (aname),
571  { }
572 
573  virtual void replace_with (jit_value *value);
574 
575  void replace_in_phi (jit_block *ablock, jit_block *with);
576 
577  // we have a new internal list, but we want to stay compatible with jit_value
578  jit_use *first_use (void) const { return jit_value::first_use (); }
579 
580  size_t use_count (void) const { return jit_value::use_count (); }
581 
582  // if a block is alive, then it might be visited during execution
583  bool alive (void) const { return malive; }
584 
585  void mark_alive (void) { malive = true; }
586 
587  // If we can merge with a successor, do so and return the now empty block
588  jit_block *maybe_merge ();
589 
590  // merge another block into this block, leaving the merge block empty
591  void merge (jit_block& merge);
592 
593  const std::string& name (void) const { return mname; }
594 
595  jit_instruction *prepend (jit_instruction *instr);
596 
597  jit_instruction *prepend_after_phi (jit_instruction *instr);
599  template <typename T>
600  T *append (T *instr)
601  {
602  internal_append (instr);
603  return instr;
604  }
606  jit_instruction *insert_before (iterator loc, jit_instruction *instr);
607 
608  jit_instruction *insert_before (jit_instruction *loc, jit_instruction *instr)
609  {
610  return insert_before (loc->location (), instr);
611  }
612 
613  jit_instruction *insert_after (iterator loc, jit_instruction *instr);
614 
615  jit_instruction *insert_after (jit_instruction *loc, jit_instruction *instr)
616  {
617  return insert_after (loc->location (), instr);
618  }
619 
620  iterator remove (iterator iter)
621  {
622  jit_instruction *instr = *iter;
623  iter = instructions.erase (iter);
624  instr->stash_parent (0, instructions.end ());
625  return iter;
626  }
628  jit_terminator *terminator (void) const;
630  // is the jump from pred alive?
631  bool branch_alive (jit_block *asucc) const;
632 
633  jit_block *successor (size_t i) const;
634 
635  size_t successor_count (void) const;
636 
637  iterator begin (void) { return instructions.begin (); }
638 
639  const_iterator begin (void) const { return instructions.begin (); }
640 
641  iterator end (void) { return instructions.end (); }
643  const_iterator end (void) const { return instructions.end (); }
644 
645  iterator phi_begin (void);
646 
647  iterator phi_end (void);
648 
649  iterator nonphi_begin (void);
650 
651  // must label before id is valid
652  size_t id (void) const { return mid; }
653 
654  // dominance frontier
655  const df_set& df (void) const { return mdf; }
656 
657  df_iterator df_begin (void) const { return mdf.begin (); }
658 
659  df_iterator df_end (void) const { return mdf.end (); }
660 
661  // label with a RPO walk
662  void label (void)
663  {
664  size_t number = 0;
665  label (mvisit_count, number);
666  }
667 
668  void label (size_t avisit_count, size_t& number);
669 
670  // See for idom computation algorithm
671  // Cooper, Keith D.; Harvey, Timothy J; and Kennedy, Ken (2001).
672  // "A Simple, Fast Dominance Algorithm"
673  void compute_idom (jit_block& entry_block)
674  {
675  bool changed;
676  entry_block.idom = &entry_block;
677  do
678  changed = update_idom (mvisit_count);
679  while (changed);
680  }
681 
682  // compute dominance frontier
683  void compute_df (void)
684  {
685  compute_df (mvisit_count);
686  }
687 
688  void create_dom_tree (void)
689  {
690  create_dom_tree (mvisit_count);
691  }
692 
693  jit_block *dom_successor (size_t idx) const
694  {
695  return dom_succ[idx];
696  }
697 
698  size_t dom_successor_count (void) const
699  {
700  return dom_succ.size ();
701  }
702 
703  // call pop_varaible on all instructions
704  void pop_all (void);
705 
706  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const;
707 
708  jit_block *maybe_split (jit_factory& factory, jit_block_list& blocks,
709  jit_block *asuccessor);
711  jit_block *maybe_split (jit_factory& factory, jit_block_list& blocks,
712  jit_block& asuccessor)
713  {
714  return maybe_split (factory, blocks, &asuccessor);
715  }
716 
717  // print dominator infomration
718  std::ostream& print_dom (std::ostream& os) const;
719 
720  virtual std::ostream& short_print (std::ostream& os) const
721  {
722  os << mname;
723  if (mid != NO_ID)
724  os << mid;
725  else
726  os << "!";
727  return os;
728  }
730  llvm::BasicBlock *to_llvm (void) const;
731 
732  std::list<jit_block *>::iterator location (void) const
733  { return mlocation; }
734 
735  void stash_location (std::list<jit_block *>::iterator alocation)
736  { mlocation = alocation; }
737 
738  // used to prevent visiting the same node twice in the graph
739  size_t visit_count (void) const { return mvisit_count; }
740 
741  // check if this node has been visited yet at the given visit count.
742  // If we have not been visited yet, mark us as visited.
743  bool visited (size_t avisit_count)
744  {
745  if (mvisit_count <= avisit_count)
746  {
747  mvisit_count = avisit_count + 1;
748  return false;
749  }
750 
751  return true;
752  }
753 
754  jit_instruction *front (void) { return instructions.front (); }
755 
756  jit_instruction *back (void) { return instructions.back (); }
757 
759 private:
760  void internal_append (jit_instruction *instr);
762  void compute_df (size_t avisit_count);
764  bool update_idom (size_t avisit_count);
766  void create_dom_tree (size_t avisit_count);
768  static jit_block *idom_intersect (jit_block *i, jit_block *j);
769 
770  size_t mvisit_count;
771  size_t mid;
772  jit_block *idom;
773  df_set mdf;
774  std::vector<jit_block *> dom_succ;
775  std::string mname;
776  instruction_list instructions;
777  bool malive;
778  std::list<jit_block *>::iterator mlocation;
779 };
781 // keeps track of phi functions that use a block on incomming edges
782 class
784 {
785 public:
786  jit_phi_incomming (void) : muser (0) { }
787 
788  jit_phi_incomming (jit_phi *auser) : muser (auser) { }
789 
791  {
792  *this = use;
793  }
794 
795  jit_phi_incomming& operator= (const jit_phi_incomming& use)
796  {
797  stash_value (use.value ());
798  muser = use.muser;
799  return *this;
800  }
801 
802  jit_phi *user (void) const { return muser; }
803 
804  jit_block *user_parent (void) const;
805 private:
806  jit_phi *muser;
807 };
808 
809 // A non-ssa variable
810 class
811 jit_variable : public jit_value
812 {
813 public:
814  jit_variable (const std::string& aname) : mname (aname), mlast_use (0) { }
816  const std::string &name (void) const { return mname; }
817 
818  // manipulate the value_stack, for use during SSA construction. The top of
819  // the value stack represents the current value for this variable
820  bool has_top (void) const
821  {
822  return ! value_stack.empty ();
823  }
824 
825  jit_value *top (void) const
826  {
827  return value_stack.top ();
828  }
829 
830  void push (jit_instruction *v)
831  {
832  value_stack.push (v);
833  mlast_use = v;
834  }
835 
836  void pop (void)
837  {
838  value_stack.pop ();
839  }
840 
841  jit_instruction *last_use (void) const
842  {
843  return mlast_use;
844  }
845 
846  void stash_last_use (jit_instruction *instr)
847  {
848  mlast_use = instr;
849  }
850 
851  // blocks in which we are used
852  void use_blocks (jit_block::df_set& result)
853  {
854  jit_use *use = first_use ();
855  while (use)
856  {
857  result.insert (use->user_parent ());
858  use = use->next ();
859  }
860  }
862  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
863  {
864  return print_indent (os, indent) << mname;
865  }
866 
868 private:
869  std::string mname;
870  std::stack<jit_value *> value_stack;
872 };
874 class
876 {
877 public:
878  jit_assign_base (jit_variable *adest) : jit_instruction (), mdest (adest) { }
879 
880  jit_assign_base (jit_variable *adest, size_t npred) : jit_instruction (npred),
881  mdest (adest) { }
882 
884  : jit_instruction (arg0, arg1), mdest (adest) { }
885 
886  jit_variable *dest (void) const { return mdest; }
887 
888  virtual void push_variable (void)
889  {
890  mdest->push (this);
891  }
892 
893  virtual void pop_variable (void)
894  {
895  mdest->pop ();
896  }
898  virtual std::ostream& short_print (std::ostream& os) const
899  {
900  if (type ())
901  jit_print (os, type ()) << ": ";
902 
903  dest ()->short_print (os);
904  return os << "#" << id ();
905  }
906 private:
907  jit_variable *mdest;
908 };
909 
910 class
912 {
913 public:
914  jit_assign (jit_variable *adest, jit_value *asrc)
915  : jit_assign_base (adest, adest, asrc), martificial (false) { }
916 
917  jit_value *overwrite (void) const
918  {
919  return argument (0);
920  }
921 
922  jit_value *src (void) const
923  {
924  return argument (1);
925  }
926 
927  // variables don't get modified in an SSA, but COW requires we modify
928  // variables. An artificial assign is for when a variable gets modified. We
929  // need an assign in the SSA, but the reference counts shouldn't be updated.
930  bool artificial (void) const { return martificial; }
931 
932  void mark_artificial (void) { martificial = true; }
933 
934  virtual bool infer (void)
935  {
936  jit_type *stype = src ()->type ();
937  if (stype != type())
938  {
939  stash_type (stype);
940  return true;
941  }
942 
943  return false;
944  }
945 
946  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
947  {
948  print_indent (os, indent) << *this << " = " << *src ();
949 
950  if (artificial ())
951  os << " [artificial]";
952 
953  return os;
954  }
957 private:
958  bool martificial;
959 };
960 
961 class
962 jit_phi : public jit_assign_base
963 {
964 public:
965  jit_phi (jit_variable *adest, size_t npred)
966  : jit_assign_base (adest, npred)
967  {
968  mincomming.reserve (npred);
969  }
970 
971  // removes arguments form dead incomming jumps
972  bool prune (void);
973 
974  void add_incomming (jit_block *from, jit_value *value)
975  {
976  push_argument (value);
977  mincomming.push_back (jit_phi_incomming (this));
978  mincomming[mincomming.size () - 1].stash_value (from);
979  }
980 
981  jit_block *incomming (size_t i) const
982  {
983  return mincomming[i].value ();
984  }
986  llvm::BasicBlock *incomming_llvm (size_t i) const
987  {
988  return incomming (i)->to_llvm ();
989  }
990 
991  virtual void construct_ssa (void) { }
992 
993  virtual bool infer (void);
994 
995  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
996  {
997  std::stringstream ss;
998  print_indent (ss, indent);
999  short_print (ss) << " phi ";
1000  std::string ss_str = ss.str ();
1001  std::string indent_str (ss_str.size (), ' ');
1002  os << ss_str;
1003 
1004  for (size_t i = 0; i < argument_count (); ++i)
1005  {
1006  if (i > 0)
1007  os << indent_str;
1008  os << "| ";
1009 
1010  os << *incomming (i) << " -> ";
1011  os << *argument (i);
1013  if (i + 1 < argument_count ())
1014  os << std::endl;
1015  }
1016 
1017  return os;
1018  }
1019 
1020  llvm::PHINode *to_llvm (void) const;
1021 
1023 private:
1024  std::vector<jit_phi_incomming> mincomming;
1025 };
1026 
1027 class
1029 {
1030 public:
1031 
1032 #define JIT_TERMINATOR_CONST(N) \
1033  jit_terminator (size_t asuccessor_count, \
1034  OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \
1035  : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), \
1036  malive (asuccessor_count, false) { }
1037 
1041 
1042 #undef JIT_TERMINATOR_CONST
1043 
1044  jit_block *successor (size_t idx = 0) const
1045  {
1046  return static_cast<jit_block *> (argument (idx));
1047  }
1048 
1049  llvm::BasicBlock *successor_llvm (size_t idx = 0) const
1050  {
1051  return successor (idx)->to_llvm ();
1052  }
1054  size_t successor_index (const jit_block *asuccessor) const;
1055 
1056  std::ostream& print_successor (std::ostream& os, size_t idx = 0) const
1057  {
1058  if (alive (idx))
1059  os << "[live] ";
1060  else
1061  os << "[dead] ";
1063  return successor (idx)->short_print (os);
1064  }
1065 
1066  // Check if the jump to successor is live
1067  bool alive (const jit_block *asuccessor) const
1068  {
1069  return alive (successor_index (asuccessor));
1070  }
1071 
1072  bool alive (size_t idx) const { return malive[idx]; }
1074  bool alive (int idx) const { return malive[idx]; }
1075 
1076  size_t successor_count (void) const { return malive.size (); }
1078  virtual bool infer (void);
1080  llvm::TerminatorInst *to_llvm (void) const;
1081 protected:
1082  virtual bool check_alive (size_t) const { return true; }
1083 private:
1084  std::vector<bool> malive;
1085 };
1086 
1087 class
1088 jit_branch : public jit_terminator
1089 {
1090 public:
1091  jit_branch (jit_block *succ) : jit_terminator (1, succ) { }
1092 
1093  virtual size_t successor_count (void) const { return 1; }
1095  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
1096  {
1097  print_indent (os, indent) << "branch: ";
1098  return print_successor (os);
1099  }
1100 
1102 };
1103 
1104 class
1106 {
1107 public:
1108  jit_cond_branch (jit_value *c, jit_block *ctrue, jit_block *cfalse)
1109  : jit_terminator (2, ctrue, cfalse, c) { }
1110 
1111  jit_value *cond (void) const { return argument (2); }
1112 
1113  std::ostream& print_cond (std::ostream& os) const
1114  {
1115  return cond ()->short_print (os);
1116  }
1117 
1118  llvm::Value *cond_llvm (void) const
1119  {
1120  return cond ()->to_llvm ();
1121  }
1123  virtual size_t successor_count (void) const { return 2; }
1124 
1125  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
1126  {
1127  print_indent (os, indent) << "cond_branch: ";
1128  print_cond (os) << ", ";
1129  print_successor (os, 0) << ", ";
1130  return print_successor (os, 1);
1131  }
1132 
1134 };
1135 
1136 class
1137 jit_call : public jit_instruction
1138 {
1139 public:
1140  jit_call (const jit_operation& (*aoperation) (void))
1141  : moperation (aoperation ())
1142  {
1143  const jit_function& ol = overload ();
1144  if (ol.valid ())
1145  stash_type (ol.result ());
1146  }
1147 
1148  jit_call (const jit_operation& aoperation) : moperation (aoperation)
1149  {
1150  const jit_function& ol = overload ();
1151  if (ol.valid ())
1152  stash_type (ol.result ());
1153  }
1154 
1155 #define JIT_CALL_CONST(N) \
1156  jit_call (const jit_operation& aoperation, \
1157  OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \
1158  : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation) { } \
1159  \
1160  jit_call (const jit_operation& (*aoperation) (void), \
1161  OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \
1162  : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation ()) \
1163  { }
1164 
1166  JIT_CALL_CONST (2)
1167  JIT_CALL_CONST (3)
1168  JIT_CALL_CONST (4)
1169 
1170 #undef JIT_CALL_CONST
1171 
1172  jit_call (const jit_operation& aoperation,
1173  const std::vector<jit_value *>& args)
1174  : jit_instruction (args), moperation (aoperation)
1175  { }
1176 
1177  const jit_operation& operation (void) const { return moperation; }
1178 
1179  bool can_error (void) const
1180  {
1181  return overload ().can_error ();
1182  }
1183 
1184  const jit_function& overload (void) const
1185  {
1186  return moperation.overload (argument_types ());
1187  }
1188 
1189  virtual bool needs_release (void) const;
1190 
1191  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
1192  {
1193  print_indent (os, indent);
1194 
1195  if (use_count ())
1196  short_print (os) << " = ";
1197  os << "call " << moperation.name () << " (";
1198 
1199  for (size_t i = 0; i < argument_count (); ++i)
1200  {
1201  print_argument (os, i);
1202  if (i + 1 < argument_count ())
1203  os << ", ";
1204  }
1205  return os << ")";
1206  }
1208  virtual bool infer (void);
1209 
1211 private:
1212  const jit_operation& moperation;
1213 };
1214 
1215 // FIXME: This is just ugly...
1216 // checks error_state, if error_state is false then goto the normal branch,
1217 // otherwise goto the error branch
1218 class
1220 {
1221 public:
1222  // Which variable is the error check for?
1223  enum variable
1224  {
1225  var_error_state,
1226  var_interrupt
1227  };
1228 
1229  static std::string variable_to_string (variable v);
1230 
1231  jit_error_check (variable var, jit_call *acheck_for, jit_block *normal,
1232  jit_block *error)
1233  : jit_terminator (2, error, normal, acheck_for), mvariable (var) { }
1234 
1235  jit_error_check (variable var, jit_block *normal, jit_block *error)
1236  : jit_terminator (2, error, normal), mvariable (var) { }
1237 
1238  variable check_variable (void) const { return mvariable; }
1239 
1240  bool has_check_for (void) const
1241  {
1242  return argument_count () == 3;
1243  }
1244 
1245  jit_call *check_for (void) const
1246  {
1247  assert (has_check_for ());
1248  return static_cast<jit_call *> (argument (2));
1249  }
1250 
1251  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const;
1252 
1254 protected:
1255  virtual bool check_alive (size_t idx) const
1256  {
1257  if (! has_check_for ())
1258  return true;
1259  return idx == 1 ? true : check_for ()->can_error ();
1260  }
1261 private:
1262  variable mvariable;
1263 };
1264 
1265 // for now only handles the 1D case
1266 class
1268 {
1269 public:
1270  class
1271  context
1272  {
1273  public:
1274  context (void) : value (0), index (0), count (0)
1275  { }
1277  context (jit_factory& factory, jit_value *avalue, size_t aindex,
1278  size_t acount);
1279 
1280  jit_value *value;
1282  jit_const_index *count;
1283  };
1284 
1285  jit_magic_end (const std::vector<context>& full_context);
1287  virtual bool infer (void);
1288 
1289  const jit_function& overload () const;
1291  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const;
1292 
1293  context resolve_context (void) const;
1294 
1295  virtual std::ostream& short_print (std::ostream& os) const
1296  {
1297  return os << "magic_end" << "#" << id ();
1298  }
1299 
1301 private:
1302  std::vector<context> contexts;
1303 };
1304 
1305 class
1307 {
1308 public:
1309  jit_extract_argument (jit_type *atype, jit_variable *adest)
1310  : jit_assign_base (adest)
1311  {
1312  stash_type (atype);
1313  }
1314 
1315  const std::string& name (void) const
1316  {
1317  return dest ()->name ();
1318  }
1319 
1320  const jit_function& overload (void) const
1321  {
1323  }
1325  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
1326  {
1327  print_indent (os, indent);
1328 
1329  return short_print (os) << " = extract " << name ();
1330  }
1331 
1333 };
1335 class
1337 {
1338 public:
1340  : jit_instruction (var), dest (var)
1341  { }
1342 
1343  const std::string& name (void) const
1344  {
1345  return dest->name ();
1346  }
1347 
1348  const jit_function& overload (void) const
1349  {
1350  return jit_typeinfo::cast (jit_typeinfo::get_any (), result_type ());
1351  }
1352 
1353  jit_value *result (void) const
1354  {
1355  return argument (0);
1356  }
1357 
1358  jit_type *result_type (void) const
1359  {
1360  return result ()->type ();
1361  }
1362 
1363  llvm::Value *result_llvm (void) const
1364  {
1365  return result ()->to_llvm ();
1366  }
1367 
1368  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
1369  {
1370  jit_value *res = result ();
1371  print_indent (os, indent) << "store ";
1372  dest->short_print (os);
1374  if (! isa<jit_variable> (res))
1375  {
1376  os << " = ";
1377  res->short_print (os);
1378  }
1379 
1380  return os;
1381  }
1384 private:
1385  jit_variable *dest;
1386 };
1387 
1388 class
1389 jit_return : public jit_instruction
1390 {
1391 public:
1392  jit_return (void) { }
1393 
1394  jit_return (jit_value *retval) : jit_instruction (retval) { }
1395 
1396  jit_value *result (void) const
1397  {
1398  return argument_count () ? argument (0) : 0;
1399  }
1400 
1401  jit_type *result_type (void) const
1402  {
1403  jit_value *res = result ();
1404  return res ? res->type () : 0;
1405  }
1406 
1407  virtual std::ostream& print (std::ostream& os, size_t indent = 0) const
1408  {
1409  print_indent (os, indent) << "return";
1410 
1411  if (result ())
1412  os << " " << *result ();
1413 
1414  return os;
1415  }
1416 
1418 };
1419 
1420 class
1422 {
1423 public:
1424  virtual ~jit_ir_walker () { }
1425 
1426 #define JIT_METH(clname) \
1427  virtual void visit (jit_ ## clname&) = 0;
1428 
1430 
1431 #undef JIT_METH
1432 };
1433 
1434 template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T, bool QUOTE>
1435 void
1437 {
1438  walker.visit (*this);
1439 }
1440 
1441 #undef JIT_VALUE_ACCEPT
1442 
1443 #endif
1444 #endif
uint32_t id
Definition: graphics.cc:11587
jit_type * result(void) const
Definition: jit-typeinfo.h:295
void stash_type(jit_type *new_ty)
Definition: jit-ir.h:227
void stash_parent(jit_block *aparent, std::list< jit_instruction * >::iterator alocation)
Definition: jit-ir.h:455
#define JIT_VISIT_IR_CLASSES
Definition: jit-ir.h:65
virtual std::ostream & short_print(std::ostream &os) const
Definition: jit-ir.h:710
virtual std::ostream & short_print(std::ostream &os) const
Definition: jit-ir.cc:218
void stash_llvm(llvm::Value *compiled)
Definition: jit-ir.h:263
virtual void replace_with(jit_value *value)
Definition: jit-ir.cc:168
jit_block * user_parent(void) const
Definition: jit-ir.cc:143
bool valid(void) const
Definition: jit-typeinfo.h:251
std::list< jit_block * >::const_iterator const_iterator
Definition: jit-ir.h:152
const std::string & name(void) const
Definition: jit-typeinfo.h:143
std::vector< jit_use > marguments
Definition: jit-ir.h:479
static jit_type * get_string(void)
Definition: jit-typeinfo.h:461
llvm::Type * to_llvm(void) const
Definition: jit-typeinfo.h:152
llvm::Value * llvm_value
Definition: jit-ir.h:276
in that an updated permutation matrix is returned Note that if var
Definition: lu.cc:606
virtual void visit(jit_block &)=0
jit_block * idom
Definition: jit-ir.h:762
jit_block * parent(void) const
Definition: jit-ir.h:446
PASS_T pass_t
Definition: jit-ir.h:515
jit_block * mparent
Definition: jit-ir.h:482
std::list< jit_instruction * >::iterator location(void) const
Definition: jit-ir.h:448
llvm::Type * type_llvm(void) const
Definition: jit-ir.h:217
#define JIT_CALL_CONST(N)
Definition: jit-ir.h:1141
#define JIT_VISIT_IR_NOTEMPLATE
Definition: jit-ir.h:42
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a number
Definition: input.cc:871
const std::string & type_name(void) const
Definition: jit-ir.h:222
virtual void accept(jit_ir_walker &walker)=0
jit_type * argument_type(size_t i) const
Definition: jit-ir.h:378
void error(const char *fmt,...)
Definition: error.cc:570
jit_type * type(void) const
Definition: jit-ir.h:215
jit_block * first_use_block(void)
Definition: jit-ir.cc:153
jit_const< octave_idx_type, jit_typeinfo::get_index > jit_const_index
Definition: jit-ir.h:88
#define JIT_CREATE(N)
Definition: jit-ir.h:122
jit_value(void)
Definition: jit-ir.h:193
bool min_worklist
Definition: jit-ir.h:280
std::list< jit_value * > value_list
Definition: jit-ir.h:104
llvm::TerminatorInst * to_llvm(void) const
Definition: jit-ir.cc:701
octave_value arg
Definition: pr-output.cc:3440
virtual bool needs_release(void) const
Definition: jit-ir.h:243
bool has_llvm(void) const
Definition: jit-ir.h:252
is any Octave expression that can be evaluated in the code context that exists at the breakpoint When the breakpoint is and execution will stop if for example because it refers to an undefined variable
Definition: debug.cc:1099
std::list< jit_instruction * >::iterator mlocation
Definition: jit-ir.h:483
void push_argument(jit_value *arg)
Definition: jit-ir.h:402
void stash_last_use(jit_instruction *alast_use)
Definition: jit-ir.h:238
void resize_arguments(size_t acount, jit_value *adefault=0)
Definition: jit-ir.h:414
llvm::Type * argument_type_llvm(size_t i) const
Definition: jit-ir.h:383
JNIEnv void * args
Definition: ov-java.cc:67
std::list< jit_instruction * > instruction_list
Definition: jit-ir.h:549
static const jit_operation & cast(jit_type *result)
Definition: jit-typeinfo.h:550
bool alive(const jit_block *asuccessor) const
Definition: jit-ir.h:1053
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
#define JIT_TERMINATOR_CONST(N)
Definition: jit-ir.h:1022
virtual void accept(jit_ir_walker &walker)
Definition: jit-ir.h:1417
size_t mid
Definition: jit-ir.h:481
jit_const< bool, jit_typeinfo::get_bool > jit_const_bool
Definition: jit-ir.h:83
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:76
#define loc(X, Y)
Definition: Screen.cpp:56
virtual void construct_ssa(void)
Definition: jit-ir.h:435
std::vector< bool > malive
Definition: jit-ir.h:1070
returns the type of the matrix and caches it for future use Called with more than one argument
Definition: matrix_type.cc:120
llvm::BasicBlock * parent_llvm(void) const
Definition: jit-ir.cc:212
jit_block * successor(size_t idx=0) const
Definition: jit-ir.h:1030
bool in_worklist(void) const
Definition: jit-ir.h:198
is false
Definition: cellfun.cc:398
octave_value retval
Definition: data.cc:6294
bool append
Definition: load-save.cc:1582
std::string print_string(void)
Definition: jit-ir.h:229
idx type
Definition: ov.cc:3129
size_t argument_count(void) const
Definition: jit-ir.h:409
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
jit_const< double, jit_typeinfo::get_scalar > jit_const_scalar
Definition: jit-ir.h:86
void stash_argument(size_t i, jit_value *arg)
Definition: jit-ir.h:397
virtual ~jit_value(void)
Definition: jit-ir.cc:149
virtual void pop_variable(void)
Definition: jit-ir.h:433
With real return the complex result
Definition: data.cc:3375
void stash_in_worklist(bool ain_worklist)
Definition: jit-ir.h:203
llvm::BasicBlock * to_llvm(void) const
Definition: jit-ir.cc:392
std::ostream & print_indent(std::ostream &os, size_t indent=0) const
Definition: jit-ir.h:269
size_t successor_index(const jit_block *asuccessor) const
Definition: jit-ir.cc:672
df_set::const_iterator df_iterator
Definition: jit-ir.h:554
LIST_T * value(void) const
Definition: jit-util.h:144
std::ostream & jit_print(std::ostream &os, jit_value *avalue)
Definition: jit-ir.cc:195
jit_const< jit_range, jit_typeinfo::get_range, const jit_range & > jit_const_range
Definition: jit-ir.h:93
virtual bool infer(void)
Definition: jit-ir.cc:683
if they have changed since they were last compiled
Definition: symtab.cc:1707
bool empty(void) const
Definition: ovl.h:98
std::vector< jit_type * > already_infered
Definition: jit-ir.h:468
octave::sys::time start
Definition: graphics.cc:11731
jit_type * ty
Definition: jit-ir.h:278
jit_use * first_use(void) const
Definition: jit-util.h:123
const std::vector< jit_type * > & argument_types(void) const
Definition: jit-ir.h:428
std::set< jit_block * > df_set
Definition: jit-ir.h:553
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
size_t successor_count(void) const
Definition: jit-ir.h:1062
jit_const< Complex, jit_typeinfo::get_complex > jit_const_complex
Definition: jit-ir.h:87
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
#define JIT_INSTRUCTION_CTOR(N)
Definition: jit-ir.h:344
jit_instruction * last_use(void) const
Definition: jit-ir.h:236
static size_t next_id(bool reset=false)
Definition: jit-ir.h:470
const value_list & constants(void) const
Definition: jit-ir.h:110
jit_instruction * mlast_use
Definition: jit-ir.h:279
llvm::Value * argument_llvm(size_t i) const
Definition: jit-ir.h:372
b
Definition: cellfun.cc:398
std::list< jit_block * >::iterator iterator
Definition: jit-ir.h:151
static void reset_ids(void)
Definition: jit-ir.h:362
jit_instruction(void)
Definition: jit-ir.h:333
jit_instruction * front(void)
Definition: jit-ir.h:744
jit_const< std::string, jit_typeinfo::get_string, const std::string &, true > jit_const_string
Definition: jit-ir.h:91
#define JIT_VALUE_ACCEPT
Definition: jit-ir.h:487
static jit_type * get_any(void)
Definition: jit-typeinfo.h:446
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable or any other valid Octave code The number of return their size
Definition: input.cc:871
jit_phi * muser
Definition: jit-ir.h:796
jit_instruction * back(void)
Definition: jit-ir.h:746
virtual bool check_alive(size_t) const
Definition: jit-ir.h:1068
virtual void push_variable(void)
Definition: jit-ir.h:431
T * create(void)
Definition: jit-ir.h:113
std::ostream & print_successor(std::ostream &os, size_t idx=0) const
Definition: jit-ir.h:1042
virtual std::ostream & short_print(std::ostream &os) const
Definition: jit-ir.h:247
NODE_T * next(void) const
Definition: jit-util.h:169
jit_instruction * user(void) const
Definition: jit-ir.h:310
llvm::BasicBlock * successor_llvm(size_t idx=0) const
Definition: jit-ir.h:1035
std::ostream & print_argument(std::ostream &os, size_t i) const
Definition: jit-ir.h:389
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
size_t index(void) const
Definition: jit-ir.h:308
void do_construct_ssa(size_t start, size_t end)
Definition: jit-ir.cc:226
With real arguments
Definition: data.cc:3375
std::ostream & operator<<(std::ostream &os, const jit_block_list &blocks)
Definition: jit-ir.cc:130
virtual std::ostream & print(std::ostream &os, size_t indent=0) const =0