Mercurial > octave-nkf
view libinterp/corefcn/jit-ir.cc @ 20620:e5f36a7854a5
Remove fuzzy matching from odeset/odeget.
* levenshtein.cc: Deleted file.
* libinterp/corefcn/module.mk: Remove levenshtein.cc from build system.
* fuzzy_compare.m: Deleted file.
* scripts/ode/module.mk: Remove fuzzy_compare.m from build system
* odeget.m: Reword docstring. Use a persistent cellstr variable to keep track
of all options. Replace fuzzy_compare() calls with combination of strcmpi and
strncmpi. Report errors relative to function odeget rather than OdePkg.
Rewrite and extend BIST tests. Add input validation BIST tests.
* odeset.m: Reword docstring. Use a persistent cellstr variable to keep track
of all options. Replace fuzzy_compare() calls with combination of strcmpi and
strncmpi. Report errors relative to function odeset rather than OdePkg.
Use more meaningful variables names and create intermediate variables with
logical names to help make code readable. Remove interactive input when
multiple property names match and just issue an error. Rewrite BIST tests.
* ode_struct_value_check.m: Remove input checking for private function which
must always be invoked correctly by caller. Use intermediate variables opt and
val to make the code more understandable. Consolidate checks on values into
single if statements. Use 'val == fix (val)' to check for integer.
* __unimplemented__.m: Removed odeset, odeget, ode45 from list.
author | Rik <rik@octave.org> |
---|---|
date | Fri, 09 Oct 2015 12:03:23 -0700 |
parents | 4197fc428c7d |
children | b65888ec820e |
line wrap: on
line source
/* Copyright (C) 2012-2015 Max Brister This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. */ // Author: Max Brister <max@2bass.com> // defines required by llvm #define __STDC_LIMIT_MACROS #define __STDC_CONSTANT_MACROS #ifdef HAVE_CONFIG_H #include <config.h> #endif #ifdef HAVE_LLVM #include "jit-ir.h" #ifdef HAVE_LLVM_IR_FUNCTION_H #include <llvm/IR/BasicBlock.h> #include <llvm/IR/Instructions.h> #else #include <llvm/BasicBlock.h> #include <llvm/Instructions.h> #endif #include "error.h" // -------------------- jit_factory -------------------- jit_factory::~jit_factory (void) { for (value_list::iterator iter = all_values.begin (); iter != all_values.end (); ++iter) delete *iter; } void jit_factory::track_value (jit_value *value) { if (value->type ()) mconstants.push_back (value); all_values.push_back (value); } // -------------------- jit_block_list -------------------- void jit_block_list::insert_after (iterator iter, jit_block *ablock) { ++iter; insert_before (iter, ablock); } void jit_block_list::insert_after (jit_block *loc, jit_block *ablock) { insert_after (loc->location (), ablock); } void jit_block_list::insert_before (iterator iter, jit_block *ablock) { iter = mlist.insert (iter, ablock); ablock->stash_location (iter); } void jit_block_list::insert_before (jit_block *loc, jit_block *ablock) { insert_before (loc->location (), ablock); } void jit_block_list::label (void) { if (mlist.size ()) { jit_block *block = mlist.back (); block->label (); } } std::ostream& jit_block_list::print (std::ostream& os, const std::string& header) const { os << "-------------------- " << header << " --------------------\n"; return os << *this; } std::ostream& jit_block_list::print_dom (std::ostream& os) const { os << "-------------------- dom info --------------------\n"; for (const_iterator iter = begin (); iter != end (); ++iter) { assert (*iter); (*iter)->print_dom (os); } os << std::endl; return os; } void jit_block_list::push_back (jit_block *b) { mlist.push_back (b); iterator iter = mlist.end (); b->stash_location (--iter); } std::ostream& operator<<(std::ostream& os, const jit_block_list& blocks) { for (jit_block_list::const_iterator iter = blocks.begin (); iter != blocks.end (); ++iter) { assert (*iter); (*iter)->print (os, 0); } return os << std::endl; } // -------------------- jit_use -------------------- jit_block * jit_use::user_parent (void) const { return muser->parent (); } // -------------------- jit_value -------------------- jit_value::~jit_value (void) {} jit_block * jit_value::first_use_block (void) { jit_use *use = first_use (); while (use) { if (! isa<jit_error_check> (use->user ())) return use->user_parent (); use = use->next (); } return 0; } void jit_value::replace_with (jit_value *value) { while (first_use ()) { jit_instruction *user = first_use ()->user (); size_t idx = first_use ()->index (); user->stash_argument (idx, value); } } #define JIT_METH(clname) \ void \ jit_ ## clname::accept (jit_ir_walker& walker) \ { \ walker.visit (*this); \ } JIT_VISIT_IR_NOTEMPLATE #undef JIT_METH std::ostream& operator<< (std::ostream& os, const jit_value& value) { return value.short_print (os); } std::ostream& jit_print (std::ostream& os, jit_value *avalue) { if (avalue) return avalue->print (os); return os << "NULL"; } // -------------------- jit_instruction -------------------- void jit_instruction::remove (void) { if (mparent) mparent->remove (mlocation); resize_arguments (0); } llvm::BasicBlock * jit_instruction::parent_llvm (void) const { return mparent->to_llvm (); } std::ostream& jit_instruction::short_print (std::ostream& os) const { if (type ()) jit_print (os, type ()) << ": "; return os << "#" << mid; } void jit_instruction::do_construct_ssa (size_t start, size_t end) { for (size_t i = start; i < end; ++i) { jit_value *arg = argument (i); jit_variable *var = dynamic_cast<jit_variable *> (arg); if (var && var->has_top ()) stash_argument (i, var->top ()); } } // -------------------- jit_block -------------------- void jit_block::replace_with (jit_value *value) { assert (isa<jit_block> (value)); jit_block *block = static_cast<jit_block *> (value); jit_value::replace_with (block); while (ILIST_T::first_use ()) { jit_phi_incomming *incomming = ILIST_T::first_use (); incomming->stash_value (block); } } void jit_block::replace_in_phi (jit_block *ablock, jit_block *with) { jit_phi_incomming *node = ILIST_T::first_use (); while (node) { jit_phi_incomming *prev = node; node = node->next (); if (prev->user_parent () == ablock) prev->stash_value (with); } } jit_block * jit_block::maybe_merge () { if (successor_count () == 1 && successor (0) != this && (successor (0)->use_count () == 1 || instructions.size () == 1)) { jit_block *to_merge = successor (0); merge (*to_merge); return to_merge; } return 0; } void jit_block::merge (jit_block& block) { // the merge block will contain a new terminator jit_terminator *old_term = terminator (); if (old_term) old_term->remove (); bool was_empty = end () == begin (); iterator merge_begin = end (); if (! was_empty) --merge_begin; instructions.splice (end (), block.instructions); if (was_empty) merge_begin = begin (); else ++merge_begin; // now merge_begin points to the start of the new instructions, we must // update their parent information for (iterator iter = merge_begin; iter != end (); ++iter) { jit_instruction *instr = *iter; instr->stash_parent (this, iter); } block.replace_with (this); } jit_instruction * jit_block::prepend (jit_instruction *instr) { instructions.push_front (instr); instr->stash_parent (this, instructions.begin ()); return instr; } jit_instruction * jit_block::prepend_after_phi (jit_instruction *instr) { // FIXME: Make this O(1) for (iterator iter = begin (); iter != end (); ++iter) { jit_instruction *temp = *iter; if (! isa<jit_phi> (temp)) { insert_before (iter, instr); return instr; } } return append (instr); } void jit_block::internal_append (jit_instruction *instr) { instructions.push_back (instr); instr->stash_parent (this, --instructions.end ()); } jit_instruction * jit_block::insert_before (iterator loc, jit_instruction *instr) { iterator iloc = instructions.insert (loc, instr); instr->stash_parent (this, iloc); return instr; } jit_instruction * jit_block::insert_after (iterator loc, jit_instruction *instr) { ++loc; iterator iloc = instructions.insert (loc, instr); instr->stash_parent (this, iloc); return instr; } jit_terminator * jit_block::terminator (void) const { assert (this); if (instructions.empty ()) return 0; jit_instruction *last = instructions.back (); return dynamic_cast<jit_terminator *> (last); } bool jit_block::branch_alive (jit_block *asucc) const { return terminator ()->alive (asucc); } jit_block * jit_block::successor (size_t i) const { jit_terminator *term = terminator (); return term->successor (i); } size_t jit_block::successor_count (void) const { jit_terminator *term = terminator (); return term ? term->successor_count () : 0; } llvm::BasicBlock * jit_block::to_llvm (void) const { return llvm::cast<llvm::BasicBlock> (llvm_value); } std::ostream& jit_block::print_dom (std::ostream& os) const { short_print (os); os << ":\n"; os << " mid: " << mid << std::endl; os << " predecessors: "; for (jit_use *use = first_use (); use; use = use->next ()) os << *use->user_parent () << " "; os << std::endl; os << " successors: "; for (size_t i = 0; i < successor_count (); ++i) os << *successor (i) << " "; os << std::endl; os << " idom: "; if (idom) os << *idom; else os << "NULL"; os << std::endl; os << " df: "; for (df_iterator iter = df_begin (); iter != df_end (); ++iter) os << **iter << " "; os << std::endl; os << " dom_succ: "; for (size_t i = 0; i < dom_succ.size (); ++i) os << *dom_succ[i] << " "; return os << std::endl; } void jit_block::compute_df (size_t avisit_count) { if (visited (avisit_count)) return; if (use_count () >= 2) { for (jit_use *use = first_use (); use; use = use->next ()) { jit_block *runner = use->user_parent (); while (runner != idom) { runner->mdf.insert (this); runner = runner->idom; } } } for (size_t i = 0; i < successor_count (); ++i) successor (i)->compute_df (avisit_count); } bool jit_block::update_idom (size_t avisit_count) { if (visited (avisit_count) || ! use_count ()) return false; bool changed = false; for (jit_use *use = first_use (); use; use = use->next ()) { jit_block *pred = use->user_parent (); changed = pred->update_idom (avisit_count) || changed; } jit_use *use = first_use (); jit_block *new_idom = use->user_parent (); use = use->next (); for (; use; use = use->next ()) { jit_block *pred = use->user_parent (); jit_block *pidom = pred->idom; if (pidom) new_idom = idom_intersect (pidom, new_idom); } if (idom != new_idom) { idom = new_idom; return true; } return changed; } void jit_block::label (size_t avisit_count, size_t& number) { if (visited (avisit_count)) return; for (jit_use *use = first_use (); use; use = use->next ()) { jit_block *pred = use->user_parent (); pred->label (avisit_count, number); } mid = number++; } void jit_block::pop_all (void) { for (iterator iter = begin (); iter != end (); ++iter) { jit_instruction *instr = *iter; instr->pop_variable (); } } std::ostream& jit_block::print (std::ostream& os, size_t indent) const { print_indent (os, indent); short_print (os) << ": %pred = "; for (jit_use *use = first_use (); use; use = use->next ()) { jit_block *pred = use->user_parent (); os << *pred; if (use->next ()) os << ", "; } os << std::endl; for (const_iterator iter = begin (); iter != end (); ++iter) { jit_instruction *instr = *iter; instr->print (os, indent + 1) << std::endl; } return os; } jit_block * jit_block::maybe_split (jit_factory& factory, jit_block_list& blocks, jit_block *asuccessor) { if (successor_count () > 1) { jit_terminator *term = terminator (); size_t idx = term->successor_index (asuccessor); jit_block *split = factory.create<jit_block> ("phi_split", mvisit_count); // place after this to ensure define before use in the blocks list blocks.insert_after (this, split); term->stash_argument (idx, split); jit_branch *br = split->append (factory.create<jit_branch> (asuccessor)); replace_in_phi (asuccessor, split); if (alive ()) { split->mark_alive (); br->infer (); } return split; } return this; } void jit_block::create_dom_tree (size_t avisit_count) { if (visited (avisit_count)) return; if (idom != this) idom->dom_succ.push_back (this); for (size_t i = 0; i < successor_count (); ++i) successor (i)->create_dom_tree (avisit_count); } jit_block * jit_block::idom_intersect (jit_block *i, jit_block *j) { while (i && j && i != j) { while (i && i->id () > j->id ()) i = i->idom; while (i && j && j->id () > i->id ()) j = j->idom; } return i ? i : j; } // -------------------- jit_phi_incomming -------------------- jit_block * jit_phi_incomming::user_parent (void) const { return muser->parent (); } // -------------------- jit_phi -------------------- bool jit_phi::prune (void) { jit_block *p = parent (); size_t new_idx = 0; jit_value *unique = argument (1); for (size_t i = 0; i < argument_count (); ++i) { jit_block *inc = incomming (i); if (inc->branch_alive (p)) { if (unique != argument (i)) unique = 0; if (new_idx != i) { stash_argument (new_idx, argument (i)); mincomming[new_idx].stash_value (inc); } ++new_idx; } } if (new_idx != argument_count ()) { resize_arguments (new_idx); mincomming.resize (new_idx); } assert (argument_count () > 0); if (unique) { replace_with (unique); return true; } return false; } bool jit_phi::infer (void) { jit_block *p = parent (); if (! p->alive ()) return false; jit_type *infered = 0; for (size_t i = 0; i < argument_count (); ++i) { jit_block *inc = incomming (i); if (inc->branch_alive (p)) infered = jit_typeinfo::join (infered, argument_type (i)); } if (infered != type ()) { stash_type (infered); return true; } return false; } llvm::PHINode * jit_phi::to_llvm (void) const { return llvm::cast<llvm::PHINode> (jit_value::to_llvm ()); } // -------------------- jit_terminator -------------------- size_t jit_terminator::successor_index (const jit_block *asuccessor) const { size_t scount = successor_count (); for (size_t i = 0; i < scount; ++i) if (successor (i) == asuccessor) return i; panic_impossible (); } bool jit_terminator::infer (void) { if (! parent ()->alive ()) return false; bool changed = false; for (size_t i = 0; i < malive.size (); ++i) if (! malive[i] && check_alive (i)) { changed = true; malive[i] = true; successor (i)->mark_alive (); } return changed; } llvm::TerminatorInst * jit_terminator::to_llvm (void) const { return llvm::cast<llvm::TerminatorInst> (jit_value::to_llvm ()); } // -------------------- jit_call -------------------- bool jit_call::needs_release (void) const { if (type () && jit_typeinfo::get_release (type ()).valid ()) { for (jit_use *use = first_use (); use; use = use->next ()) { jit_assign *assign = dynamic_cast<jit_assign *> (use->user ()); if (assign && assign->artificial ()) return false; } return true; } return false; } bool jit_call::infer (void) { // FIXME: explain algorithm for (size_t i = 0; i < argument_count (); ++i) { already_infered[i] = argument_type (i); if (! already_infered[i]) return false; } jit_type *infered = moperation.result (already_infered); if (! infered && use_count ()) { std::stringstream ss; ss << "Missing overload in type inference for "; print (ss, 0); throw jit_fail_exception (ss.str ()); } if (infered != type ()) { stash_type (infered); return true; } return false; } // -------------------- jit_error_check -------------------- std::string jit_error_check::variable_to_string (variable v) { switch (v) { case var_error_state: return "error_state"; case var_interrupt: return "interrupt"; default: panic_impossible (); } } std::ostream& jit_error_check::print (std::ostream& os, size_t indent) const { print_indent (os, indent) << "error_check " << variable_to_string (mvariable) << ", "; if (has_check_for ()) os << "<for> " << *check_for () << ", "; print_successor (os << "<normal> ", 1) << ", "; return print_successor (os << "<error> ", 0); } // -------------------- jit_magic_end -------------------- jit_magic_end::context::context (jit_factory& factory, jit_value *avalue, size_t aindex, size_t acount) : value (avalue), index (factory.create<jit_const_index> (aindex)), count (factory.create<jit_const_index> (acount)) {} jit_magic_end::jit_magic_end (const std::vector<context>& full_context) : contexts (full_context) { resize_arguments (contexts.size ()); size_t i; std::vector<context>::const_iterator iter; for (iter = contexts.begin (), i = 0; iter != contexts.end (); ++iter, ++i) stash_argument (i, iter->value); } jit_magic_end::context jit_magic_end::resolve_context (void) const { size_t idx; for (idx = 0; idx < contexts.size (); ++idx) { jit_type *ctx_type = contexts[idx].value->type (); if (! ctx_type || ctx_type->skip_paren ()) break; } if (idx >= contexts.size ()) idx = 0; context ret = contexts[idx]; ret.value = argument (idx); return ret; } bool jit_magic_end::infer (void) { jit_type *new_type = overload ().result (); if (new_type != type ()) { stash_type (new_type); return true; } return false; } std::ostream& jit_magic_end::print (std::ostream& os, size_t indent) const { context ctx = resolve_context (); short_print (print_indent (os, indent)) << " (" << *ctx.value << ", "; return os << *ctx.index << ", " << *ctx.count << ")"; } const jit_function& jit_magic_end::overload () const { const context& ctx = resolve_context (); return jit_typeinfo::end (ctx.value, ctx.index, ctx.count); } #endif