Mercurial > hg > octave-nkf
view src/jit-ir.cc @ 15063:36cbcc37fdb8
Refactor configure.ac to make it more understandable.
Use common syntax for messages in config.h
Correct typos, refer to libraries in all caps, use two spaces after period.
Follow Autoconf guidelines and place general tests before specific tests.
* configure.ac, m4/acinclude.m4: Use common syntax for messages in config.h
Correct typos, refer to libraries in all caps, use two spaces after period.
Follow Autoconf guidelines and place general tests before specific tests.
author | Rik <rik@octave.org> |
---|---|
date | Tue, 31 Jul 2012 10:28:51 -0700 |
parents | bc32288f4a42 |
children | df4538e3b50b |
line wrap: on
line source
/* Copyright (C) 2012 Max Brister <max@2bass.com> 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/>. */ // 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" #include <llvm/BasicBlock.h> #include <llvm/Instructions.h> #include "error.h" #include "pt-jit.h" // -------------------- 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::pop_all (void) { for (iterator iter = begin (); iter != end (); ++iter) { jit_instruction *instr = *iter; instr->pop_variable (); } } jit_block * jit_block::maybe_split (jit_convert& convert, jit_block *asuccessor) { if (successor_count () > 1) { jit_terminator *term = terminator (); size_t idx = term->successor_index (asuccessor); jit_block *split = convert.create<jit_block> ("phi_split", mvisit_count); // try to place splits where they make sense if (id () < asuccessor->id ()) convert.insert_before (asuccessor, split); else convert.insert_after (this, split); term->stash_argument (idx, split); jit_branch *br = split->append (convert.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::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_magic_end -------------------- const jit_function& jit_magic_end::overload () const { jit_value *ctx = resolve_context (); if (ctx) return jit_typeinfo::end (ctx->type ()); static jit_function null_ret; return null_ret; } jit_value * jit_magic_end::resolve_context (void) const { // FIXME: We need to have a way of marking functions so we can skip them here return argument_count () ? argument (0) : 0; } bool jit_magic_end::infer (void) { jit_type *new_type = overload ().result (); if (new_type != type ()) { stash_type (new_type); return true; } return false; } #endif