25 #if ! defined (octave_jit_ir_h) 26 #define octave_jit_ir_h 1 28 #include "octave-config.h" 30 #if defined (HAVE_LLVM) 45 #define JIT_VISIT_IR_NOTEMPLATE \ 48 JIT_METH (cond_branch); \ 50 JIT_METH (extract_argument); \ 51 JIT_METH (store_argument); \ 54 JIT_METH (variable); \ 55 JIT_METH (error_check); \ 60 #define JIT_VISIT_IR_CONST \ 61 JIT_METH (const_bool); \ 62 JIT_METH (const_scalar); \ 63 JIT_METH (const_complex); \ 64 JIT_METH (const_index); \ 65 JIT_METH (const_string); \ 66 JIT_METH (const_range) 68 #define JIT_VISIT_IR_CLASSES \ 69 JIT_VISIT_IR_NOTEMPLATE \ 73 #define JIT_METH(cname) \ 81 class jit_instruction;
84 template <
typename T, jit_type *(*EXTRACT_T)(void),
typename PASS_T = T,
115 template <
typename T,
typename ...Args>
118 T *ret =
new T (args...);
158 void insert_after (iterator iter,
jit_block *ablock);
162 void insert_before (iterator iter,
jit_block *ablock);
168 std::ostream& print (std::ostream&
os,
const std::string& header)
const;
170 std::ostream& print_dom (std::ostream&
os)
const;
187 : m_llvm_value (0), m_type (0), m_last_use (0), m_in_worklist (
false)
194 return m_in_worklist;
199 m_in_worklist = ain_worklist;
207 virtual void replace_with (
jit_value *m_value);
213 return m_type ? m_type->to_llvm () :
nullptr;
218 return m_type->name ();
225 std::stringstream ss;
234 m_last_use = alast_use;
239 virtual std::ostream& print (std::ostream&
os,
size_t indent = 0)
const = 0;
242 {
return print (
os); }
253 assert (m_llvm_value);
266 for (
size_t i = 0;
i < indent * 8; ++
i)
306 size_t index (
void)
const {
return m_index; }
312 std::list<jit_block *> user_parent_location (
void)
const;
317 PARENT_T::stash_value (avalue);
335 : m_id (next_id ()), m_parent (0)
339 : m_id (next_id ()), m_parent (0)
341 m_already_infered.reserve (nargs);
342 m_arguments.reserve (nargs);
345 template <
typename ...Args>
347 : m_already_infered (1 + sizeof... (other_args)),
348 m_arguments (1 + sizeof... (other_args)),
349 m_id (next_id ()), m_parent (nullptr)
351 stash_argument (0, arg1, other_args...);
355 : m_already_infered (aarguments.size ()), m_arguments (aarguments.size ()),
356 m_id (next_id ()), m_parent (0)
358 for (
size_t i = 0;
i < aarguments.size (); ++
i)
359 stash_argument (
i, aarguments[
i]);
369 return m_arguments[
i].value ();
386 return argument_type (
i)->to_llvm ();
399 m_arguments[
i].stash_value (
arg,
this,
i);
402 template <
typename ...Args>
405 m_arguments[
i].stash_value (arg1,
this,
i);
406 stash_argument (++
i, aargs...);
411 m_arguments.push_back (
jit_use ());
412 stash_argument (m_arguments.size () - 1,
arg);
413 m_already_infered.push_back (0);
418 return m_arguments.size ();
423 size_t old = m_arguments.size ();
424 m_arguments.resize (acount);
425 m_already_infered.resize (acount);
428 for (
size_t i = old;
i < acount; ++
i)
429 stash_argument (
i, adefault);
432 const std::vector<jit_use>&
arguments (
void)
const {
return m_arguments; }
436 {
return m_already_infered; }
444 do_construct_ssa (0, argument_count ());
447 virtual bool infer (
void) {
return false; }
451 virtual std::ostream& short_print (std::ostream&
os)
const;
455 std::list<jit_instruction *>::iterator
location (
void)
const 460 llvm::BasicBlock * parent_llvm (
void)
const;
463 std::list<jit_instruction *>::iterator alocation)
466 m_location = alocation;
469 size_t id (
void)
const {
return m_id; }
474 void do_construct_ssa (
size_t start,
size_t end);
482 static size_t ret = 0;
497 #define JIT_VALUE_ACCEPT \ 498 virtual void accept (jit_ir_walker& walker); 512 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 514 print_indent (
os, indent);
521 template <
typename T, jit_type *(*EXTRACT_T)(
void),
typename PASS_T,
bool QUOTE>
523 jit_const :
public jit_value
531 stash_type (EXTRACT_T ());
534 PASS_T
value (
void)
const {
return m_value; }
536 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 538 print_indent (
os, indent);
572 static const size_t NO_ID =
static_cast<size_t> (-1);
575 : m_visit_count (avisit_count), m_id (NO_ID), m_idom (0), m_name (aname),
589 bool alive (
void)
const {
return m_alive; }
605 template <
typename T>
608 internal_append (instr);
616 return insert_before (
loc->location (), instr);
623 return insert_after (
loc->location (), instr);
629 iter = m_instructions.erase (iter);
637 bool branch_alive (
jit_block *asucc)
const;
641 size_t successor_count (
void)
const;
651 iterator phi_begin (
void);
653 iterator phi_end (
void);
655 iterator nonphi_begin (
void);
658 size_t id (
void)
const {
return m_id; }
671 label (m_visit_count,
number);
674 void label (
size_t avisit_count,
size_t&
number);
682 entry_block.
m_idom = &entry_block;
684 changed = update_idom (m_visit_count);
691 compute_df (m_visit_count);
696 create_dom_tree (m_visit_count);
701 return m_dom_succ[idx];
706 return m_dom_succ.size ();
712 virtual std::ostream& print (std::ostream&
os,
size_t indent = 0)
const;
720 return maybe_split (factory, blocks, &asuccessor);
724 std::ostream& print_dom (std::ostream&
os)
const;
736 llvm::BasicBlock * to_llvm (
void)
const;
738 std::list<jit_block *>::iterator
location (
void)
const 739 {
return m_location; }
742 { m_location = alocation; }
751 if (m_visit_count <= avisit_count)
753 m_visit_count = avisit_count + 1;
770 void compute_df (
size_t avisit_count);
772 bool update_idom (
size_t avisit_count);
774 void create_dom_tree (
size_t avisit_count);
806 stash_value (use.
value ());
834 return ! value_stack.empty ();
839 return value_stack.top ();
844 value_stack.push (v);
874 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 876 return print_indent (
os, indent) << m_name;
922 dest ()->short_print (
os);
923 return os <<
'#' <<
id ();
971 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 973 print_indent (
os, indent) << *
this <<
" = " << *src ();
976 os <<
" [artificial]";
996 m_incoming.reserve (npred);
1004 push_argument (
value);
1006 m_incoming[m_incoming.size () - 1].stash_value (from);
1011 return m_incoming[
i].value ();
1016 return incoming (
i)->to_llvm ();
1021 virtual bool infer (
void);
1023 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1025 std::stringstream ss;
1026 print_indent (ss, indent);
1027 short_print (ss) <<
" phi ";
1032 for (
size_t i = 0;
i < argument_count (); ++
i)
1038 os << *incoming (
i) <<
" -> ";
1041 if (
i + 1 < argument_count ())
1048 llvm::PHINode * to_llvm (
void)
const;
1062 template <
typename ...Args>
1065 m_alive (asuccessor_count,
false) { }
1074 return successor (idx)->to_llvm ();
1077 size_t successor_index (
const jit_block *asuccessor)
const;
1086 return successor (idx)->short_print (
os);
1092 return alive (successor_index (asuccessor));
1095 bool alive (
size_t idx)
const {
return m_alive[idx]; }
1097 bool alive (
int idx)
const {
return m_alive[idx]; }
1101 virtual bool infer (
void);
1103 llvm::TerminatorInst * to_llvm (
void)
const;
1123 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1125 print_indent (
os, indent) <<
"branch: ";
1126 return print_successor (
os);
1144 return cond ()->short_print (
os);
1149 return cond ()->to_llvm ();
1154 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1156 print_indent (
os, indent) <<
"cond_branch: ";
1157 print_cond (
os) <<
", ";
1158 print_successor (
os, 0) <<
", ";
1159 return print_successor (
os, 1);
1171 : m_operation (aoperation ())
1175 stash_type (ol.
result ());
1182 stash_type (ol.
result ());
1185 template <
typename ...Args>
1191 template <
typename ...Args>
1198 const std::vector<jit_value *>& args)
1206 return overload ().can_error ();
1211 return m_operation.overload (argument_types ());
1214 virtual bool needs_release (
void)
const;
1216 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1218 print_indent (
os, indent);
1221 short_print (
os) <<
" = ";
1222 os <<
"call " << m_operation.
name () <<
" (";
1224 for (
size_t i = 0;
i < argument_count (); ++
i)
1226 print_argument (
os,
i);
1227 if (
i + 1 < argument_count ())
1233 virtual bool infer (
void);
1270 return argument_count () == 3;
1275 assert (has_check_for ());
1279 virtual std::ostream& print (std::ostream&
os,
size_t indent = 0)
const;
1287 if (! has_check_for ())
1289 return idx == 1 ? true : check_for ()->can_error ();
1308 context (
void) : m_value (0), m_index (0), m_count (0) { }
1320 virtual bool infer (
void);
1324 virtual std::ostream& print (std::ostream&
os,
size_t indent = 0)
const;
1326 context resolve_context (
void)
const;
1330 return os <<
"magic_end" <<
'#' <<
id ();
1353 return dest ()->name ();
1361 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1363 print_indent (
os, indent);
1365 return short_print (
os) <<
" = extract " <<
name ();
1382 return m_dest->name ();
1397 return result ()->type ();
1402 return result ()->to_llvm ();
1405 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1408 print_indent (
os, indent) <<
"store ";
1409 m_dest->short_print (
os);
1411 if (! isa<jit_variable> (res))
1438 return argument_count () ?
argument (0) :
nullptr;
1444 return res ? res->
type () :
nullptr;
1447 virtual std::ostream&
print (std::ostream&
os,
size_t indent = 0)
const 1449 print_indent (
os, indent) <<
"return";
1467 #define JIT_METH(clname) \ 1468 virtual void visit (jit_ ## clname&) = 0; 1475 template <
typename T, jit_type *(*EXTRACT_T)(
void),
typename PASS_T,
bool QUOTE>
1479 walker.
visit (*
this);
1482 #undef JIT_VALUE_ACCEPT
jit_call(const jit_operation &aoperation)
llvm::BasicBlock * successor_llvm(size_t idx=0) const
jit_call(const jit_operation &aoperation, const std::vector< jit_value *> &args)
virtual bool needs_release(void) const
jit_block * dom_successor(size_t idx) const
void use_blocks(jit_block::df_set &result)
void create_dom_tree(void)
jit_instruction(size_t nargs)
#define JIT_VISIT_IR_CLASSES
instruction_list::iterator iterator
std::vector< jit_phi_incoming > m_incoming
virtual void construct_ssa(void)
const_iterator end(void) const
void stash_argument(size_t i, jit_value *arg)
virtual void visit(jit_block &)=0
void stash_argument(size_t i, jit_value *arg1, Args... aargs)
std::list< jit_block * > m_list
void compute_idom(jit_block &entry_block)
jit_use * first_use(void) const
jit_call(const jit_operation &(*aoperation)(void))
jit_value * src(void) const
jit_instruction(jit_value *arg1, Args... other_args)
const_iterator begin(void) const
const std::string & name(void) const
jit_const< bool, jit_typeinfo::get_bool > jit_const_bool
jit_instruction(const std::vector< jit_value *> &aarguments)
void resize_arguments(size_t acount, jit_value *adefault=nullptr)
virtual void pop_variable(void)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
bool has_check_for(void) const
jit_value * result(void) const
jit_cond_branch(jit_value *c, jit_block *ctrue, jit_block *cfalse)
void push(jit_instruction *v)
jit_phi * user(void) const
bool artificial(void) const
jit_block(const std::string &aname, size_t avisit_count=0)
void stash_value(jit_value *avalue, jit_instruction *auser=nullptr, size_t aindex=-1)
bool alive(const jit_block *asuccessor) const
static const jit_operation & cast(jit_type *result)
llvm::Value * argument_llvm(size_t i) const
virtual std::ostream & short_print(std::ostream &os) const
df_set::const_iterator df_iterator
const_iterator begin(void) const
for fields that display a single number
jit_block * parent(void) const
jit_phi_incoming(jit_phi *auser)
jit_instruction * m_last_use
std::list< jit_value * > value_list
jit_return(jit_value *retval)
void push_argument(jit_value *arg)
const value_list & constants(void) const
std::vector< context > m_contexts
jit_error_check(variable var, jit_block *normal, jit_block *error)
#define JIT_VISIT_IR_NOTEMPLATE
llvm::Type * argument_type_llvm(size_t i) const
jit_assign(jit_variable *adest, jit_value *asrc)
void error(const char *fmt,...)
jit_phi_incoming(const jit_phi_incoming &use)
jit_const< jit_range, jit_typeinfo::get_range, const jit_range & > jit_const_range
bool alive(size_t idx) const
iterator erase(iterator iter)
T * create(const Args &... args)
virtual void push_variable(void)
df_iterator df_begin(void) const
size_t argument_count(void) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
void stash_last_use(jit_instruction *alast_use)
jit_instruction * back(void)
static llvm::LLVMContext & context
llvm::Value * m_llvm_value
jit_assign_base(jit_variable *adest, size_t npred)
jit_value * overwrite(void) const
jit_value * top(void) const
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
void stash_parent(jit_block *aparent, std::list< jit_instruction *>::iterator alocation)
std::ostream & jit_print(std::ostream &os, jit_value *avalue)
llvm::Value * result_llvm(void) const
std::ostream & print_indent(std::ostream &os, size_t indent=0) const
const std::string & name(void) const
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
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
virtual void push_variable(void)
NODE_T * next(void) const
std::list< jit_block * >::iterator location(void) const
jit_const< double, jit_typeinfo::get_scalar > jit_const_scalar
jit_const< octave_idx_type, jit_typeinfo::get_index > jit_const_index
void stash_llvm(llvm::Value *compiled)
std::list< jit_block * >::const_iterator const_iterator
bool visited(size_t avisit_count)
jit_type * argument_type(size_t i) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
virtual void accept(jit_ir_walker &walker)
variable check_variable(void) const
virtual std::ostream & short_print(std::ostream &os) const
virtual void pop_variable(void)
void stash_in_worklist(bool ain_worklist)
virtual std::ostream & short_print(std::ostream &os) const
jit_call(const jit_operation &(*aoperation)(void), jit_value *arg1, Args... other_args)
const std::vector< jit_type * > & argument_types(void) const
nd deftypefn *std::string name
virtual size_t successor_count(void) const
bool has_llvm(void) const
std::ostream & operator<<(std::ostream &os, const jit_block_list &blocks)
jit_block * back(void) const
jit_instruction * last_use(void) const
void stash_type(jit_type *new_type)
jit_call * check_for(void) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
std::set< jit_block * > df_set
void stash_last_use(jit_instruction *instr)
virtual size_t successor_count(void) const
bool in_worklist(void) const
size_t use_count(void) const
jit_type * result_type(void) const
jit_value * argument(size_t i) const
void mark_artificial(void)
jit_const_index * m_index
jit_variable * dest(void) const
llvm::Type * type_llvm(void) const
returns the type of the matrix and caches it for future use Called with more than one argument
df_iterator df_end(void) const
const_iterator end(void) const
jit_instruction * last_use(void) const
jit_call(const jit_operation &aoperation, jit_value *arg1, Args... other_args)
jit_instruction * m_last_use
jit_block * successor(size_t idx=0) const
virtual void construct_ssa(void)
std::string print_string(void)
jit_type * type(void) const
std::list< jit_instruction * >::iterator m_location
jit_instruction * front(void)
jit_use * first_use(void) const
std::vector< jit_type * > m_already_infered
jit_variable(const std::string &aname)
jit_terminator(size_t asuccessor_count, Args... args)
size_t visit_count(void) const
std::list< jit_block * >::iterator iterator
instruction_list m_instructions
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
const jit_function & overload(void) const
jit_argument(jit_type *atype, llvm::Value *avalue)
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
instruction_list::const_iterator const_iterator
jit_internal_node< jit_value, jit_use > PARENT_T
std::list< jit_block * >::iterator m_location
std::string name(void) const
static void reset_ids(void)
jit_internal_list< jit_block, jit_phi_incoming > ILIST_T
jit_type * result_type(void) const
llvm::Value * cond_llvm(void) const
std::list< jit_instruction * >::iterator location(void) const
const df_set & df(void) const
With real return the complex result
size_t dom_successor_count(void) const
std::vector< jit_use > m_arguments
std::stack< jit_value * > value_stack
jit_block * front(void) const
std::ostream & print_successor(std::ostream &os, size_t idx=0) const
void add_incoming(jit_block *from, jit_value *value)
jit_type * result(void) const
jit_block * user_parent(void) const
const jit_operation & m_operation
if they have changed since they were last compiled
static jit_type * get_string(void)
static jit_type * get_any(void)
jit_block * maybe_split(jit_factory &factory, jit_block_list &blocks, jit_block &asuccessor)
llvm::Value * to_llvm(void) const
jit_phi(jit_variable *adest, size_t npred)
static size_t next_id(bool reset=false)
bool alive(int idx) const
std::vector< jit_block * > m_dom_succ
size_t successor_count(void) const
jit_block * incoming(size_t i) const
const std::vector< jit_use > & arguments(void) const
const std::string & name(void) const
jit_instruction * insert_after(jit_instruction *loc, jit_instruction *instr)
jit_const< Complex, jit_typeinfo::get_complex > jit_const_complex
jit_error_check(variable var, jit_call *acheck_for, jit_block *normal, jit_block *error)
jit_const< std::string, jit_typeinfo::get_string, const std::string &, true > jit_const_string
jit_branch(jit_block *succ)
LIST_T * value(void) const
bool can_error(void) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_value * cond(void) const
jit_use(const jit_use &use)
const jit_function & overload(void) const
jit_assign_base(jit_variable *adest)
jit_instruction * user(void) const
std::ostream & print_cond(std::ostream &os) const
jit_store_argument(jit_variable *var)
std::vector< bool > m_alive
std::list< jit_instruction * > instruction_list
size_t use_count(void) const
jit_assign_base(jit_variable *adest, jit_value *arg0, jit_value *arg1)
virtual std::ostream & short_print(std::ostream &os) const
std::ostream & print_argument(std::ostream &os, size_t i) const
virtual std::ostream & print(std::ostream &os, size_t indent=0) const
jit_const_index * m_count
jit_value * result(void) const
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
nd group nd example For each display the value
virtual ~jit_ir_walker(void)
virtual bool check_alive(size_t idx) const
const std::string & type_name(void) const
llvm::BasicBlock * incoming_llvm(size_t i) const
jit_instruction * insert_before(jit_instruction *loc, jit_instruction *instr)
virtual bool check_alive(size_t) const
void stash_location(std::list< jit_block *>::iterator alocation)
const jit_operation & operation(void) const