26 #if ! defined (octave_jit_ir_h)
27 #define octave_jit_ir_h 1
29 #include "octave-config.h"
31 #if defined (HAVE_LLVM)
46 #define JIT_VISIT_IR_NOTEMPLATE \
49 JIT_METH (cond_branch); \
51 JIT_METH (extract_argument); \
52 JIT_METH (store_argument); \
55 JIT_METH (variable); \
56 JIT_METH (error_check); \
61 #define JIT_VISIT_IR_CONST \
62 JIT_METH (const_bool); \
63 JIT_METH (const_scalar); \
64 JIT_METH (const_complex); \
65 JIT_METH (const_index); \
66 JIT_METH (const_string); \
67 JIT_METH (const_range)
69 #define JIT_VISIT_IR_CLASSES \
70 JIT_VISIT_IR_NOTEMPLATE \
74 #define JIT_METH(cname) \
82 class jit_instruction;
85 template <
typename T, jit_type *(*EXTRACT_T)(void),
typename PASS_T = T,
95 const std::string&,
true>
117 template <
typename T,
typename ...Args>
120 T *ret =
new T (args...);
160 void insert_after (iterator iter,
jit_block *ablock);
164 void insert_before (iterator iter,
jit_block *ablock);
170 std::ostream& print (std::ostream& os,
const std::string& header)
const;
172 std::ostream& print_dom (std::ostream& os)
const;
189 : m_llvm_value (0), m_type (0), m_last_use (0), m_in_worklist (false)
196 return m_in_worklist;
201 m_in_worklist = ain_worklist;
209 virtual void replace_with (
jit_value *m_value);
215 return m_type ? m_type->to_llvm () :
nullptr;
220 return m_type->name ();
227 std::stringstream ss;
236 m_last_use = alast_use;
241 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const = 0;
244 {
return print (os); }
255 assert (m_llvm_value);
261 m_llvm_value = compiled;
268 for (
size_t i = 0; i < indent * 8; ++i)
308 size_t index (
void)
const {
return m_index; }
319 PARENT_T::stash_value (avalue);
337 : m_id (next_id ()), m_parent (0)
341 : m_id (next_id ()), m_parent (0)
343 m_already_infered.reserve (nargs);
344 m_arguments.reserve (nargs);
347 template <
typename ...Args>
349 : m_already_infered (1 + sizeof... (other_args)),
350 m_arguments (1 + sizeof... (other_args)),
351 m_id (next_id ()), m_parent (nullptr)
353 stash_argument (0, arg1, other_args...);
357 : m_already_infered (aarguments.size ()), m_arguments (aarguments.size ()),
358 m_id (next_id ()), m_parent (0)
360 for (
size_t i = 0; i < aarguments.size (); ++i)
361 stash_argument (i, aarguments[i]);
371 return m_arguments[i].value ();
376 assert (argument (i));
377 return argument (i)->to_llvm ();
382 return argument (i)->type ();
387 assert (argument (i));
388 return argument_type (i)->to_llvm ();
394 return argument (i)->short_print (os);
401 m_arguments[i].stash_value (arg,
this, i);
404 template <
typename ...Args>
407 m_arguments[i].stash_value (arg1,
this, i);
408 stash_argument (++i, aargs...);
413 m_arguments.push_back (
jit_use ());
414 stash_argument (m_arguments.size () - 1, arg);
415 m_already_infered.push_back (0);
420 return m_arguments.size ();
425 size_t old = m_arguments.size ();
426 m_arguments.resize (acount);
427 m_already_infered.resize (acount);
430 for (
size_t i = old; i < acount; ++i)
431 stash_argument (i, adefault);
434 const std::vector<jit_use>&
arguments (
void)
const {
return m_arguments; }
438 {
return m_already_infered; }
446 do_construct_ssa (0, argument_count ());
449 virtual bool infer (
void) {
return false; }
453 virtual std::ostream& short_print (std::ostream& os)
const;
457 std::list<jit_instruction *>::iterator
location (
void)
const
462 llvm::BasicBlock * parent_llvm (
void)
const;
465 std::list<jit_instruction *>::iterator alocation)
468 m_location = alocation;
471 size_t id (
void)
const {
return m_id; }
476 void do_construct_ssa (
size_t start,
size_t end);
484 static size_t ret = 0;
499 #define JIT_VALUE_ACCEPT \
500 virtual void accept (jit_ir_walker& walker);
514 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
516 print_indent (os, indent);
523 template <
typename T, jit_type *(*EXTRACT_T)(
void),
typename PASS_T,
bool QUOTE>
533 stash_type (EXTRACT_T ());
536 PASS_T
value (
void)
const {
return m_value; }
538 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
540 print_indent (os, indent);
574 static const size_t NO_ID =
static_cast<size_t> (-1);
576 jit_block (
const std::string& aname,
size_t avisit_count = 0)
577 : m_visit_count (avisit_count), m_id (NO_ID), m_idom (0), m_name (aname),
581 virtual void replace_with (
jit_value *value);
591 bool alive (
void)
const {
return m_alive; }
601 const std::string&
name (
void)
const {
return m_name; }
607 template <
typename T>
610 internal_append (instr);
618 return insert_before (
loc->location (), instr);
625 return insert_after (
loc->location (), instr);
631 iter = m_instructions.erase (iter);
639 bool branch_alive (
jit_block *asucc)
const;
643 size_t successor_count (
void)
const;
660 size_t id (
void)
const {
return m_id; }
673 label (m_visit_count, number);
676 void label (
size_t avisit_count,
size_t& number);
684 entry_block.
m_idom = &entry_block;
686 changed = update_idom (m_visit_count);
693 compute_df (m_visit_count);
698 create_dom_tree (m_visit_count);
703 return m_dom_succ[idx];
708 return m_dom_succ.size ();
714 virtual std::ostream& print (std::ostream& os,
size_t indent = 0)
const;
722 return maybe_split (factory, blocks, &asuccessor);
726 std::ostream& print_dom (std::ostream& os)
const;
738 llvm::BasicBlock * to_llvm (
void)
const;
740 std::list<jit_block *>::iterator
location (
void)
const
741 {
return m_location; }
744 { m_location = alocation; }
753 if (m_visit_count <= avisit_count)
755 m_visit_count = avisit_count + 1;
772 void compute_df (
size_t avisit_count);
774 bool update_idom (
size_t avisit_count);
776 void create_dom_tree (
size_t avisit_count);
808 stash_value (use.
value ());
828 jit_variable (
const std::string& aname) : m_name (aname), m_last_use (0) { }
830 const std::string&
name (
void)
const {
return m_name; }
836 return ! value_stack.empty ();
841 return value_stack.top ();
846 value_stack.push (v);
876 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
878 return print_indent (os, indent) << m_name;
924 dest ()->short_print (os);
925 return os <<
'#' << id ();
973 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
975 print_indent (os, indent) << *
this <<
" = " << *src ();
978 os <<
" [artificial]";
998 m_incoming.reserve (npred);
1006 push_argument (value);
1008 m_incoming[m_incoming.size () - 1].stash_value (from);
1013 return m_incoming[i].value ();
1018 return incoming (i)->to_llvm ();
1023 virtual bool infer (
void);
1025 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1027 std::stringstream ss;
1028 print_indent (ss, indent);
1029 short_print (ss) <<
" phi ";
1030 std::string ss_str = ss.str ();
1031 std::string indent_str (ss_str.size (),
' ');
1034 for (
size_t i = 0; i < argument_count (); ++i)
1040 os << *incoming (i) <<
" -> ";
1041 os << *argument (i);
1043 if (i + 1 < argument_count ())
1050 llvm::PHINode * to_llvm (
void)
const;
1064 template <
typename ...Args>
1067 m_alive (asuccessor_count, false) { }
1071 return static_cast<jit_block *
> (argument (idx));
1076 return successor (idx)->to_llvm ();
1079 size_t successor_index (
const jit_block *asuccessor)
const;
1088 return successor (idx)->short_print (os);
1094 return alive (successor_index (asuccessor));
1097 bool alive (
size_t idx)
const {
return m_alive[idx]; }
1099 bool alive (
int idx)
const {
return m_alive[idx]; }
1103 virtual bool infer (
void);
1105 llvm::TerminatorInst * to_llvm (
void)
const;
1125 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1127 print_indent (os, indent) <<
"branch: ";
1128 return print_successor (os);
1146 return cond ()->short_print (os);
1151 return cond ()->to_llvm ();
1156 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1158 print_indent (os, indent) <<
"cond_branch: ";
1159 print_cond (os) <<
", ";
1160 print_successor (os, 0) <<
", ";
1161 return print_successor (os, 1);
1173 : m_operation (aoperation ())
1177 stash_type (ol.
result ());
1184 stash_type (ol.
result ());
1187 template <
typename ...Args>
1193 template <
typename ...Args>
1200 const std::vector<jit_value *>& args)
1208 return overload ().can_error ();
1213 return m_operation.overload (argument_types ());
1216 virtual bool needs_release (
void)
const;
1218 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1220 print_indent (os, indent);
1223 short_print (os) <<
" = ";
1224 os <<
"call " << m_operation.name () <<
" (";
1226 for (
size_t i = 0; i < argument_count (); ++i)
1228 print_argument (os, i);
1229 if (i + 1 < argument_count ())
1235 virtual bool infer (
void);
1259 static std::string variable_to_string (variable v);
1272 return argument_count () == 3;
1277 assert (has_check_for ());
1278 return static_cast<jit_call *
> (argument (2));
1281 virtual std::ostream& print (std::ostream& os,
size_t indent = 0)
const;
1289 if (! has_check_for ())
1291 return idx == 1 ? true : check_for ()->can_error ();
1310 context (
void) : m_value (0), m_index (0), m_count (0) { }
1322 virtual bool infer (
void);
1326 virtual std::ostream& print (std::ostream& os,
size_t indent = 0)
const;
1328 context resolve_context (
void)
const;
1332 return os <<
"magic_end" <<
'#' << id ();
1353 const std::string&
name (
void)
const
1355 return dest ()->name ();
1363 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1365 print_indent (os, indent);
1367 return short_print (os) <<
" = extract " <<
name ();
1382 const std::string&
name (
void)
const
1384 return m_dest->name ();
1394 return argument (0);
1399 return result ()->type ();
1404 return result ()->to_llvm ();
1407 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1410 print_indent (os, indent) <<
"store ";
1411 m_dest->short_print (os);
1413 if (! isa<jit_variable> (res))
1440 return argument_count () ? argument (0) :
nullptr;
1446 return res ? res->
type () :
nullptr;
1449 virtual std::ostream&
print (std::ostream& os,
size_t indent = 0)
const
1451 print_indent (os, indent) <<
"return";
1454 os <<
' ' << *result ();
1469 #define JIT_METH(clname) \
1470 virtual void visit (jit_ ## clname&) = 0;
1477 template <
typename T, jit_type *(*EXTRACT_T)(
void),
typename PASS_T,
bool QUOTE>
1481 walker.
visit (*
this);
1484 #undef JIT_VALUE_ACCEPT
jit_argument(jit_type *atype, llvm::Value *avalue)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_variable * dest(void) const
virtual void pop_variable(void)
virtual void push_variable(void)
jit_assign_base(jit_variable *adest)
virtual std::ostream & short_print(std::ostream &os) const
jit_assign_base(jit_variable *adest, size_t npred)
jit_assign_base(jit_variable *adest, jit_value *arg0, jit_value *arg1)
jit_value * src(void) const
void mark_artificial(void)
jit_value * overwrite(void) const
bool artificial(void) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_assign(jit_variable *adest, jit_value *asrc)
iterator erase(iterator iter)
jit_block * front(void) const
const_iterator end(void) const
std::list< jit_block * >::const_iterator const_iterator
jit_block * back(void) const
std::list< jit_block * > m_list
std::list< jit_block * >::iterator iterator
const_iterator begin(void) const
void create_dom_tree(void)
instruction_list::const_iterator const_iterator
iterator nonphi_begin(void)
jit_instruction * back(void)
jit_instruction * insert_after(jit_instruction *loc, jit_instruction *instr)
instruction_list m_instructions
df_set::const_iterator df_iterator
size_t dom_successor_count(void) const
jit_block * maybe_split(jit_factory &factory, jit_block_list &blocks, jit_block &asuccessor)
instruction_list::iterator iterator
const df_set & df(void) const
iterator remove(iterator iter)
const_iterator begin(void) const
size_t visit_count(void) const
virtual std::ostream & short_print(std::ostream &os) const
std::list< jit_instruction * > instruction_list
bool visited(size_t avisit_count)
jit_instruction * insert_before(jit_instruction *loc, jit_instruction *instr)
std::set< jit_block * > df_set
jit_internal_list< jit_block, jit_phi_incoming > ILIST_T
void stash_location(std::list< jit_block * >::iterator alocation)
df_iterator df_begin(void) const
void compute_idom(jit_block &entry_block)
std::list< jit_block * >::iterator m_location
const std::string & name(void) const
jit_use * first_use(void) const
size_t use_count(void) const
jit_instruction * front(void)
jit_block * dom_successor(size_t idx) const
jit_block(const std::string &aname, size_t avisit_count=0)
std::vector< jit_block * > m_dom_succ
df_iterator df_end(void) const
const_iterator end(void) const
std::list< jit_block * >::iterator location(void) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_branch(jit_block *succ)
virtual size_t successor_count(void) const
jit_call(const jit_operation &aoperation)
jit_call(const jit_operation &aoperation, jit_value *arg1, Args... other_args)
const jit_function & overload(void) const
jit_call(const jit_operation &(*aoperation)(void), jit_value *arg1, Args... other_args)
jit_call(const jit_operation &(*aoperation)(void))
bool can_error(void) const
const jit_operation & m_operation
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
const jit_operation & operation(void) const
jit_call(const jit_operation &aoperation, const std::vector< jit_value * > &args)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_value * cond(void) const
std::ostream & print_cond(std::ostream &os) const
jit_cond_branch(jit_value *c, jit_block *ctrue, jit_block *cfalse)
llvm::Value * cond_llvm(void) const
virtual size_t successor_count(void) const
virtual void accept(jit_ir_walker &walker)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
virtual bool check_alive(size_t idx) const
jit_error_check(variable var, jit_block *normal, jit_block *error)
variable check_variable(void) const
bool has_check_for(void) const
jit_error_check(variable var, jit_call *acheck_for, jit_block *normal, jit_block *error)
jit_call * check_for(void) const
const value_list & constants(void) const
T * create(const Args &... args)
std::list< jit_value * > value_list
jit_type * result(void) const
void stash_parent(jit_block *aparent, std::list< jit_instruction * >::iterator alocation)
jit_type * argument_type(size_t i) const
llvm::Value * argument_llvm(size_t i) const
const std::vector< jit_use > & arguments(void) const
jit_instruction(size_t nargs)
jit_instruction(jit_value *arg1, Args... other_args)
virtual void push_variable(void)
llvm::Type * argument_type_llvm(size_t i) const
void stash_argument(size_t i, jit_value *arg)
std::ostream & print_argument(std::ostream &os, size_t i) const
void resize_arguments(size_t acount, jit_value *adefault=nullptr)
std::vector< jit_type * > m_already_infered
std::list< jit_instruction * >::iterator m_location
size_t argument_count(void) const
std::list< jit_instruction * >::iterator location(void) const
void stash_argument(size_t i, jit_value *arg1, Args... aargs)
std::vector< jit_use > m_arguments
const std::vector< jit_type * > & argument_types(void) const
jit_block * parent(void) const
virtual void pop_variable(void)
void push_argument(jit_value *arg)
jit_value * argument(size_t i) const
jit_instruction(const std::vector< jit_value * > &aarguments)
static void reset_ids(void)
virtual void construct_ssa(void)
static size_t next_id(bool reset=false)
jit_use * first_use(void) const
size_t use_count(void) const
LIST_T * value(void) const
NODE_T * next(void) const
virtual ~jit_ir_walker(void)
virtual void visit(jit_block &)=0
jit_const_index * m_index
jit_const_index * m_count
std::vector< context > m_contexts
virtual std::ostream & short_print(std::ostream &os) const
jit_phi_incoming(jit_phi *auser)
jit_phi * user(void) const
jit_phi_incoming(const jit_phi_incoming &use)
std::vector< jit_phi_incoming > m_incoming
llvm::BasicBlock * incoming_llvm(size_t i) const
jit_phi(jit_variable *adest, size_t npred)
void add_incoming(jit_block *from, jit_value *value)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
virtual void construct_ssa(void)
jit_block * incoming(size_t i) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_return(jit_value *retval)
jit_value * result(void) const
jit_type * result_type(void) const
const jit_function & overload(void) const
const std::string & name(void) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_value * result(void) const
jit_store_argument(jit_variable *var)
jit_type * result_type(void) const
llvm::Value * result_llvm(void) const
llvm::BasicBlock * successor_llvm(size_t idx=0) const
bool alive(int idx) const
std::ostream & print_successor(std::ostream &os, size_t idx=0) const
bool alive(const jit_block *asuccessor) const
size_t successor_count(void) const
virtual bool check_alive(size_t) const
jit_terminator(size_t asuccessor_count, Args... args)
jit_block * successor(size_t idx=0) const
std::vector< bool > m_alive
bool alive(size_t idx) const
static const jit_operation & cast(jit_type *result)
static jit_type * get_any(void)
static jit_type * get_string(void)
jit_block * user_parent(void) const
jit_use(const jit_use &use)
jit_instruction * user(void) const
void stash_value(jit_value *avalue, jit_instruction *auser=nullptr, size_t aindex=-1)
std::list< jit_block * > user_parent_location(void) const
jit_internal_node< jit_value, jit_use > PARENT_T
void stash_llvm(llvm::Value *compiled)
virtual bool needs_release(void) const
bool has_llvm(void) const
virtual void accept(jit_ir_walker &walker)=0
bool in_worklist(void) const
jit_type * type(void) const
void stash_type(jit_type *new_type)
jit_instruction * last_use(void) const
void stash_in_worklist(bool ain_worklist)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const =0
void stash_last_use(jit_instruction *alast_use)
llvm::Value * to_llvm(void) const
llvm::Value * m_llvm_value
llvm::Type * type_llvm(void) const
std::string print_string(void)
const std::string & type_name(void) const
virtual std::ostream & short_print(std::ostream &os) const
jit_instruction * m_last_use
std::ostream & print_indent(std::ostream &os, size_t indent=0) const
jit_instruction * last_use(void) const
void push(jit_instruction *v)
void stash_last_use(jit_instruction *instr)
jit_instruction * m_last_use
void use_blocks(jit_block::df_set &result)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
const std::string & name(void) const
jit_variable(const std::string &aname)
jit_value * top(void) const
std::stack< jit_value * > value_stack
void error(const char *fmt,...)
#define JIT_VISIT_IR_CLASSES
#define JIT_VISIT_IR_NOTEMPLATE
std::ostream & operator<<(std::ostream &os, const jit_block_list &blocks)
jit_const< double, jit_typeinfo::get_scalar > jit_const_scalar
jit_const< octave_idx_type, jit_typeinfo::get_index > jit_const_index
static llvm::LLVMContext & context
jit_const< bool, jit_typeinfo::get_bool > jit_const_bool
std::ostream & jit_print(std::ostream &os, jit_value *avalue)
jit_const< Complex, jit_typeinfo::get_complex > jit_const_complex
jit_const< std::string, jit_typeinfo::get_string, const std::string &, true > jit_const_string
jit_const< jit_range, jit_typeinfo::get_range, const jit_range & > jit_const_range
octave_value::octave_value(const Array< char > &chm, char type) return retval