# HG changeset patch # User Max Brister # Date 1336357050 21600 # Node ID f25d2224fa02a074a5f4e3c64c5568f72f111b1f # Parent de72463862c458d99f13d63dd484412b1c5f634f Initial JIT support build-aux/common.mk: Add llvm flags. configure.ac: Link with llvm. src/Makefile: Add pt-jit. src/link-deps.mk: Link with llvm. src/oct-conf.in.h: Add llvm flags. src/toplev.cc: Add llvm flags. src/pt-eval.cc: Try to jit statements. src/pt-jit.cc: New file. src/pt-jit.h: New file diff --git a/build-aux/common.mk b/build-aux/common.mk --- a/build-aux/common.mk +++ b/build-aux/common.mk @@ -541,6 +541,9 @@ -e "s|%OCTAVE_CONF_MAGICK_CPPFLAGS%|\"${MAGICK_CPPFLAGS}\"|" \ -e "s|%OCTAVE_CONF_MAGICK_LDFLAGS%|\"${MAGICK_LDFLAGS}\"|" \ -e "s|%OCTAVE_CONF_MAGICK_LIBS%|\"${MAGICK_LIBS}\"|" \ + -e "s|%OCTAVE_CONF_LLVM_CPPFLAGS%|\"${LLVM_CPPFLAGS}\"|" \ + -e "s|%OCTAVE_CONF_LLVM_LDFLAGS%|\"${LLVM_LDFLAGS}\"|" \ + -e "s|%OCTAVE_CONF_LLVM_LIBS%|\"${LLVM_LIBS}\"|" \ -e 's|%OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%|\"@MKOCTFILE_DL_LDFLAGS@\"|' \ -e "s|%OCTAVE_CONF_OCTAVE_LINK_DEPS%|\"${OCTAVE_LINK_DEPS}\"|" \ -e "s|%OCTAVE_CONF_OCTAVE_LINK_OPTS%|\"${OCTAVE_LINK_OPTS}\"|" \ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -711,6 +711,58 @@ [ZLIB library not found. Octave will not be able to save or load compressed data files or HDF5 files.], [zlib.h], [gzclearerr]) +### Check for the llvm library +dnl +dnl +dnl llvm is odd and has its own pkg-config like script. We should probably check +dnl for existance and +dnl + +LLVM_CONFIG=llvm-config +LLVM_CPPFLAGS= +LLVM_LDFLAGS= +LLVM_LIBS= + +LLVM_LDFLAGS=`$LLVM_CONFIG --ldflags` +LLVM_LIBS=`$LLVM_CONFIG --libs` +LLVM_CPPFLAGS=`$LLVM_CONFIG --cxxflags` + +warn_llvm="LLVM library fails tests. JIT compilation will be disabled." + +save_CPPFLAGS="$CPPFLAGS" +save_LIBS="$LIBS" +save_LDFLAGS="$LDFLAGS" +CPPFLAGS="$LLVM_CPPFLAGS $CPPFLAGS" +LIBS="$LLVM_LIBS $LIBS" +LDFLAGS="$LLVM_LDFLAGS $LDFLAGS" +AC_LANG_PUSH(C++) + AC_CHECK_HEADER([llvm/LLVMContext.h], [ + AC_MSG_CHECKING([for llvm::getGlobalContext in llvm/LLVMContext.h]) + AC_TRY_LINK([#include ], [llvm::getGlobalContext ()], [ + AC_MSG_RESULT(yes) + warn_llvm= + ], [ + AC_MSG_RESULT(no) + ]) + ]) +AC_LANG_POP(C++) +CPPFLAGS="$save_CPPFLAGS" +LIBS="$save_LIBS" +LDFLAGS="$save_LDFLAGS" + +if test -z "$warn_llvm"; then + AC_DEFINE(HAVE_LLVM, 1, [Define if LLVM is available.]) +else + LLVM_CPPFLAGS= + LLVM_LDFLAGS= + LLVM_LIBS= +fi +AC_DEFINE(HAVE_LLVM, 1, [Define if LLVM is available.]) + +AC_SUBST(LLVM_CPPFLAGS) +AC_SUBST(LLVM_LDFLAGS) +AC_SUBST(LLVM_LIBS) + ### Check for HDF5 library. save_CPPFLAGS="$CPPFLAGS" @@ -2222,6 +2274,9 @@ Magick++ CPPFLAGS: $MAGICK_CPPFLAGS Magick++ LDFLAGS: $MAGICK_LDFLAGS Magick++ libraries: $MAGICK_LIBS + LLVM CPPFLAGS: $LLVM_CPPFLAGS + LLVM LDFLAGS: $LLVM_LDFLAGS + LLVM Libraries: $LLVM_LIBS HDF5 CPPFLAGS: $HDF5_CPPFLAGS HDF5 LDFLAGS: $HDF5_LDFLAGS HDF5 libraries: $HDF5_LIBS @@ -2392,6 +2447,11 @@ warn_msg_printed=true fi +if test -n "$warn_llvm"; then + AC_MSG_WARN([$warn_llvm]) + warn_msg_printed=true +fi + if test -n "$warn_ghostscript"; then AC_MSG_WARN([$warn_ghostscript]) warn_msg_printed=true diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -220,6 +220,7 @@ pt-fcn-handle.h \ pt-id.h \ pt-idx.h \ + pt-jit.h \ pt-jump.h \ pt-loop.h \ pt-mat.h \ @@ -392,6 +393,7 @@ pt-fcn-handle.cc \ pt-id.cc \ pt-idx.cc \ + pt-jit.cc \ pt-jump.cc \ pt-loop.cc \ pt-mat.cc \ diff --git a/src/link-deps.mk b/src/link-deps.mk --- a/src/link-deps.mk +++ b/src/link-deps.mk @@ -13,14 +13,16 @@ $(Z_LIBS) \ $(OPENGL_LIBS) \ $(X11_LIBS) \ - $(CARBON_LIBS) + $(CARBON_LIBS) \ + $(LLVM_LIBS) LIBOCTINTERP_LINK_OPTS = \ $(GRAPHICS_LDFLAGS) \ $(FT2_LDFLAGS) \ $(HDF5_LDFLAGS) \ $(Z_LDFLAGS) \ - $(REGEX_LDFLAGS) + $(REGEX_LDFLAGS) \ + $(LLVM_LDFLAGS) OCT_LINK_DEPS = diff --git a/src/oct-conf.in.h b/src/oct-conf.in.h --- a/src/oct-conf.in.h +++ b/src/oct-conf.in.h @@ -384,6 +384,18 @@ #define OCTAVE_CONF_MAGICK_LIBS %OCTAVE_CONF_MAGICK_LIBS% #endif +#ifndef OCTAVE_CONF_LLVM_CPPFLAGS +#define OCTAVE_CONF_LLVM_CPPFLAGS %OCTAVE_CONF_LLVM_CPPFLAGS% +#endif + +#ifndef OCTAVE_CONF_LLVM_LDFLAGS +#define OCTAVE_CONF_LLVM_LDFLAGS %OCTAVE_CONF_LLVM_LDFLAGS% +#endif + +#ifndef OCTAVE_CONF_LLVM_LIBS +#define OCTAVE_CONF_LLVM_LIBS %OCTAVE_CONF_LLVM_LIBS% +#endif + #ifndef OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS #define OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS% #endif diff --git a/src/pt-eval.cc b/src/pt-eval.cc --- a/src/pt-eval.cc +++ b/src/pt-eval.cc @@ -44,6 +44,10 @@ #include "symtab.h" #include "unwind-prot.h" +//FIXME: This should be part of tree_evaluator +#include "pt-jit.h" +static tree_jit jiter; + static tree_evaluator std_evaluator; tree_evaluator *current_evaluator = &std_evaluator; @@ -680,6 +684,9 @@ tree_command *cmd = stmt.command (); tree_expression *expr = stmt.expression (); + if (! Vdebugging && ! Vecho_executing_commands && jiter.execute (stmt)) + return; + if (cmd || expr) { if (statement_context == function || statement_context == script) diff --git a/src/pt-jit.cc b/src/pt-jit.cc new file mode 100644 --- /dev/null +++ b/src/pt-jit.cc @@ -0,0 +1,703 @@ +/* + +Copyright (C) 2009-2012 John W. Eaton + +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 +. + +*/ + +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pt-jit.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ov-fcn-handle.h" +#include "ov-usr-fcn.h" +#include "pt-all.h" + +using namespace llvm; + +//FIXME: Move into tree_jit +static IRBuilder<> builder (getGlobalContext ()); + +extern "C" void +octave_print_double (const char *name, double value) +{ + // FIXME: We should avoid allocating a new octave_scalar each time + octave_value ov (value); + ov.print_with_name (octave_stdout, name); +} + +tree_jit::tree_jit (void) : context (getGlobalContext ()), engine (0) +{ + InitializeNativeTarget (); + InitializeNativeTargetAsmPrinter (); + module = new Module ("octave", context); +} + +tree_jit::~tree_jit (void) +{ + delete module; +} + +bool +tree_jit::execute (tree& tee) +{ + if (!engine) + { + engine = ExecutionEngine::createJIT (module); + + // initialize pass manager + pass_manager = new FunctionPassManager (module); + pass_manager->add (new TargetData(*engine->getTargetData ())); + pass_manager->add (createBasicAliasAnalysisPass ()); + pass_manager->add (createPromoteMemoryToRegisterPass ()); + pass_manager->add (createInstructionCombiningPass ()); + pass_manager->add (createReassociatePass ()); + pass_manager->add (createGVNPass ()); + pass_manager->add (createCFGSimplificationPass ()); + pass_manager->doInitialization (); + + // create external functions + Type *vtype = Type::getVoidTy (context); + std::vector pd_args (2); + pd_args[0] = Type::getInt8PtrTy (context); + pd_args[1] = Type::getDoubleTy (context); + FunctionType *print_double_ty = FunctionType::get (vtype, pd_args, false); + print_double = Function::Create (print_double_ty, + Function::ExternalLinkage, + "octave_print_double", module); + engine->addGlobalMapping (print_double, + reinterpret_cast(&octave_print_double)); + } + + if (!engine) + // sometimes this fails during early initialization + return false; + + // find function + function_info *finfo; + finfo_map_iterator iter = compiled_functions.find (&tee); + + if (iter == compiled_functions.end ()) + finfo = compile (tee); + else + finfo = iter->second; + + return finfo->execute (); +} + +tree_jit::function_info* +tree_jit::compile (tree& tee) +{ + value_stack.clear (); + variables.clear (); + + // setup function + std::vector args (2); + args[0] = Type::getInt1PtrTy (context); + args[1] = Type::getDoublePtrTy (context); + FunctionType *ft = FunctionType::get (Type::getVoidTy (context), args, false); + Function *compiling = Function::Create (ft, Function::ExternalLinkage, + "test_fn", module); + + entry_block = BasicBlock::Create (context, "entry", compiling); + BasicBlock *body = BasicBlock::Create (context, "body", + compiling); + builder.SetInsertPoint (body); + + // convert tree to LLVM IR + try + { + tee.accept (*this); + } + catch (const jit_fail_exception&) + { + //FIXME: cleanup + return compiled_functions[&tee] = new function_info (); + } + + // copy input arguments + builder.SetInsertPoint (entry_block); + + Function::arg_iterator arg_iter = compiling->arg_begin (); + Value *arg_defined = arg_iter; + Value *arg_value = ++arg_iter; + + arg_defined->setName ("arg_defined"); + arg_value->setName ("arg_value"); + + size_t idx = 0; + std::vector arg_names; + std::vector arg_used; + for (var_map_iterator iter = variables.begin (); iter != variables.end (); + ++iter, ++idx) + { + arg_names.push_back (iter->first); + arg_used.push_back (iter->second.use); + + Value *gep_defined = builder.CreateConstInBoundsGEP1_32 (arg_defined, idx); + Value *defined = builder.CreateLoad (gep_defined); + builder.CreateStore (defined, iter->second.defined); + + Value *gep_value = builder.CreateConstInBoundsGEP1_32 (arg_value, idx); + Value *value = builder.CreateLoad (gep_value); + builder.CreateStore (value, iter->second.value); + } + builder.CreateBr (body); + + // copy output arguments + BasicBlock *cleanup = BasicBlock::Create (context, "cleanup", compiling); + builder.SetInsertPoint (body); + builder.CreateBr (cleanup); + builder.SetInsertPoint (cleanup); + + idx = 0; + for (var_map_iterator iter = variables.begin (); iter != variables.end (); + ++iter, ++idx) + { + Value *gep_defined = builder.CreateConstInBoundsGEP1_32 (arg_defined, idx); + Value *defined = builder.CreateLoad (iter->second.defined); + builder.CreateStore (defined, gep_defined); + + Value *gep_value = builder.CreateConstInBoundsGEP1_32 (arg_value, idx); + Value *value = builder.CreateLoad (iter->second.value, iter->first); + builder.CreateStore (value, gep_value); + } + + builder.CreateRetVoid (); + + // print what we compiled (for debugging) + // we leave this in for now, as other people might want to view the ir created + // should be removed eventually though + const bool debug_print_ir = false; + if (debug_print_ir) + { + raw_os_ostream os (std::cout); + std::cout << "Compiling --------------------\n"; + tree_print_code tpc (std::cout); + std::cout << typeid (tee).name () << std::endl; + tee.accept (tpc); + std::cout << "\n--------------------\n"; + + std::cout << "llvm_ir\n"; + compiling->print (os); + std::cout << "--------------------\n"; + } + + // compile code + verifyFunction (*compiling); + pass_manager->run (*compiling); + + if (debug_print_ir) + { + raw_os_ostream os (std::cout); + std::cout << "optimized llvm_ir\n"; + compiling->print (os); + std::cout << "--------------------\n"; + } + + jit_function fun = + reinterpret_cast (engine->getPointerToFunction (compiling)); + + return compiled_functions[&tee] = new function_info (fun, arg_names, arg_used); +} + +tree_jit::variable_info +tree_jit::find (const std::string &name, bool use) +{ + var_map_iterator iter = variables.find (name); + if (iter == variables.end ()) + { + // we currently just assume everything is a double + Type *dbl = Type::getDoubleTy (context); + Type *bol = Type::getInt1Ty (context); + IRBuilder<> tmpB (entry_block, entry_block->begin ()); + + variable_info vinfo; + vinfo.defined = tmpB.CreateAlloca (bol, 0); + vinfo.value = tmpB.CreateAlloca (dbl, 0, name); + vinfo.use = use; + variables[name] = vinfo; + return vinfo; + } + else + { + iter->second.use = iter->second.use || use; + return iter->second; + } +} + +void +tree_jit::do_assign (variable_info vinfo, llvm::Value *value) +{ + // create assign expression + Value *result = builder.CreateStore (value, vinfo.value); + value_stack.push_back (result); + + // update defined for lhs + Type *btype = Type::getInt1Ty (context); + Value *btrue = ConstantInt::get (btype, APInt (1, 1)); + builder.CreateStore (btrue, vinfo.defined); +} + +void +tree_jit::emit_print (const std::string& vname, llvm::Value *value) +{ + Value *pname = builder.CreateGlobalStringPtr (vname); + builder.CreateCall2 (print_double, pname, value); +} + +void +tree_jit::visit_anon_fcn_handle (tree_anon_fcn_handle&) +{ + fail (); +} + +void +tree_jit::visit_argument_list (tree_argument_list&) +{ + fail (); +} + +void +tree_jit::visit_binary_expression (tree_binary_expression& be) +{ + tree_expression *lhs = be.lhs (); + tree_expression *rhs = be.rhs (); + if (lhs && rhs) + { + lhs->accept (*this); + rhs->accept (*this); + + Value *lhsv = value_stack.back (); + value_stack.pop_back (); + + Value *rhsv = value_stack.back (); + value_stack.pop_back (); + + Value *result; + switch (be.op_type ()) + { + case octave_value::op_add: + result = builder.CreateFAdd (lhsv, rhsv); + break; + case octave_value::op_sub: + result = builder.CreateFSub (lhsv, rhsv); + break; + case octave_value::op_mul: + result = builder.CreateFMul (lhsv, rhsv); + break; + case octave_value::op_div: + result = builder.CreateFDiv (lhsv, rhsv); + break; + default: + fail (); + } + + value_stack.push_back (result); + } + else + fail (); +} + +void +tree_jit::visit_break_command (tree_break_command&) +{ + fail (); +} + +void +tree_jit::visit_colon_expression (tree_colon_expression&) +{ + fail (); +} + +void +tree_jit::visit_continue_command (tree_continue_command&) +{ + fail (); +} + +void +tree_jit::visit_global_command (tree_global_command&) +{ + fail (); +} + +void +tree_jit::visit_persistent_command (tree_persistent_command&) +{ + fail (); +} + +void +tree_jit::visit_decl_elt (tree_decl_elt&) +{ + fail (); +} + +void +tree_jit::visit_decl_init_list (tree_decl_init_list&) +{ + fail (); +} + +void +tree_jit::visit_simple_for_command (tree_simple_for_command&) +{ + fail (); +} + +void +tree_jit::visit_complex_for_command (tree_complex_for_command&) +{ + fail (); +} + +void +tree_jit::visit_octave_user_script (octave_user_script&) +{ + fail (); +} + +void +tree_jit::visit_octave_user_function (octave_user_function&) +{ + fail (); +} + +void +tree_jit::visit_octave_user_function_header (octave_user_function&) +{ + fail (); +} + +void +tree_jit::visit_octave_user_function_trailer (octave_user_function&) +{ + fail (); +} + +void +tree_jit::visit_function_def (tree_function_def&) +{ + fail (); +} + +void +tree_jit::visit_identifier (tree_identifier& ti) +{ + octave_value ov = ti.do_lookup (); + if (ov.is_function ()) + fail (); + + std::string name = ti.name (); + variable_info vinfo = find (ti.name (), true); + + // TODO check defined + + Value *load_value = builder.CreateLoad (vinfo.value, name); + value_stack.push_back (load_value); +} + +void +tree_jit::visit_if_clause (tree_if_clause&) +{ + fail (); +} + +void +tree_jit::visit_if_command (tree_if_command&) +{ + fail (); +} + +void +tree_jit::visit_if_command_list (tree_if_command_list&) +{ + fail (); +} + +void +tree_jit::visit_index_expression (tree_index_expression&) +{ + fail (); +} + +void +tree_jit::visit_matrix (tree_matrix&) +{ + fail (); +} + +void +tree_jit::visit_cell (tree_cell&) +{ + fail (); +} + +void +tree_jit::visit_multi_assignment (tree_multi_assignment&) +{ + fail (); +} + +void +tree_jit::visit_no_op_command (tree_no_op_command&) +{ + fail (); +} + +void +tree_jit::visit_constant (tree_constant& tc) +{ + octave_value v = tc.rvalue1 (); + if (v.is_real_scalar () && v.is_double_type ()) + { + double dv = v.double_value (); + Value *lv = ConstantFP::get (context, APFloat (dv)); + value_stack.push_back (lv); + } + else + fail (); +} + +void +tree_jit::visit_fcn_handle (tree_fcn_handle&) +{ + fail (); +} + +void +tree_jit::visit_parameter_list (tree_parameter_list&) +{ + fail (); +} + +void +tree_jit::visit_postfix_expression (tree_postfix_expression&) +{ + fail (); +} + +void +tree_jit::visit_prefix_expression (tree_prefix_expression&) +{ + fail (); +} + +void +tree_jit::visit_return_command (tree_return_command&) +{ + fail (); +} + +void +tree_jit::visit_return_list (tree_return_list&) +{ + fail (); +} + +void +tree_jit::visit_simple_assignment (tree_simple_assignment& tsa) +{ + // only support an identifier as lhs + tree_identifier *lhs = dynamic_cast (tsa.left_hand_side ()); + if (!lhs) + fail (); + + variable_info lhsv = find (lhs->name (), false); + + // resolve rhs as normal + tree_expression *rhs = tsa.right_hand_side (); + rhs->accept (*this); + + Value *rhsv = value_stack.back (); + value_stack.pop_back (); + + do_assign (lhsv, rhsv); + + if (tsa.print_result ()) + emit_print (lhs->name (), rhsv); +} + +void +tree_jit::visit_statement (tree_statement& stmt) +{ + tree_command *cmd = stmt.command (); + tree_expression *expr = stmt.expression (); + + if (cmd) + cmd->accept (*this); + else + { + // TODO deal with printing + + // stolen from tree_evaluator::visit_statement + bool do_bind_ans = false; + + if (expr->is_identifier ()) + { + tree_identifier *id = dynamic_cast (expr); + + do_bind_ans = (! id->is_variable ()); + } + else + do_bind_ans = (! expr->is_assignment_expression ()); + + expr->accept (*this); + + if (do_bind_ans) + { + Value *rhs = value_stack.back (); + value_stack.pop_back (); + + variable_info ans = find ("ans", false); + do_assign (ans, rhs); + } + else if (expr->is_identifier () && expr->print_result ()) + { + // FIXME: ugly hack, we need to come up with a way to pass + // nargout to visit_identifier + emit_print (expr->name (), value_stack.back ()); + } + + + value_stack.pop_back (); + } +} + +void +tree_jit::visit_statement_list (tree_statement_list&) +{ + fail (); +} + +void +tree_jit::visit_switch_case (tree_switch_case&) +{ + fail (); +} + +void +tree_jit::visit_switch_case_list (tree_switch_case_list&) +{ + fail (); +} + +void +tree_jit::visit_switch_command (tree_switch_command&) +{ + fail (); +} + +void +tree_jit::visit_try_catch_command (tree_try_catch_command&) +{ + fail (); +} + +void +tree_jit::visit_unwind_protect_command (tree_unwind_protect_command&) +{ + fail (); +} + +void +tree_jit::visit_while_command (tree_while_command&) +{ + fail (); +} + +void +tree_jit::visit_do_until_command (tree_do_until_command&) +{ + fail (); +} + +void +tree_jit::fail (void) +{ + throw jit_fail_exception (); +} + +tree_jit::function_info::function_info (void) : function (0) +{} + +tree_jit::function_info::function_info (jit_function fun, + const std::vector& args, + const std::vector& arg_used) : + function (fun), arguments (args), argument_used (arg_used) +{} + +bool tree_jit::function_info::execute () +{ + if (! function) + return false; + + // FIXME: we are doing hash lookups every time, this has got to be slow + unwind_protect up; + bool *args_defined = new bool[arguments.size ()]; // vector sucks + up.add_delete (args_defined); + + std::vector args_values (arguments.size ()); + for (size_t i = 0; i < arguments.size (); ++i) + { + octave_value ov = symbol_table::varval (arguments[i]); + + if (argument_used[i]) + { + if (! (ov.is_double_type () && ov.is_real_scalar ())) + return false; + + args_defined[i] = ov.is_defined (); + args_values[i] = ov.double_value (); + } + else + args_defined[i] = false; + } + + function (args_defined, &args_values[0]); + + for (size_t i = 0; i < arguments.size (); ++i) + if (args_defined[i]) + symbol_table::varref (arguments[i]) = octave_value (args_values[i]); + + return true; +} diff --git a/src/pt-jit.h b/src/pt-jit.h new file mode 100644 --- /dev/null +++ b/src/pt-jit.h @@ -0,0 +1,201 @@ +/* + +Copyright (C) 2009-2012 John W. Eaton + +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 +. + +*/ + +#if !defined (octave_tree_jit_h) +#define octave_tree_jit_h 1 + +#include +#include +#include + +#include "pt-walk.h" + +class jit_fail_exception : public std::exception {}; + +// LLVM forward declares +namespace llvm +{ + class Value; + class Module; + class FunctionPassManager; + class ExecutionEngine; + class Function; + class BasicBlock; + class LLVMContext; +} + +class tree; + +class +OCTINTERP_API +tree_jit : private tree_walker +{ +public: + tree_jit (void); + + ~tree_jit (void); + + bool execute (tree& tee); + private: + typedef void (*jit_function)(bool*, double*); + + class function_info + { + public: + function_info (void); + function_info (jit_function fn, const std::vector& args, + const std::vector& args_used); + + bool execute (); + private: + jit_function function; + std::vector arguments; + + // is the argument used? or is it just declared? + std::vector argument_used; + }; + + struct variable_info + { + llvm::Value *defined; + llvm::Value *value; + bool use; + }; + + function_info *compile (tree& tee); + + variable_info find (const std::string &name, bool use); + + void do_assign (variable_info vinfo, llvm::Value *value); + + void emit_print (const std::string& vname, llvm::Value *value); + + // tree_walker + void visit_anon_fcn_handle (tree_anon_fcn_handle&); + + void visit_argument_list (tree_argument_list&); + + void visit_binary_expression (tree_binary_expression&); + + void visit_break_command (tree_break_command&); + + void visit_colon_expression (tree_colon_expression&); + + void visit_continue_command (tree_continue_command&); + + void visit_global_command (tree_global_command&); + + void visit_persistent_command (tree_persistent_command&); + + void visit_decl_elt (tree_decl_elt&); + + void visit_decl_init_list (tree_decl_init_list&); + + void visit_simple_for_command (tree_simple_for_command&); + + void visit_complex_for_command (tree_complex_for_command&); + + void visit_octave_user_script (octave_user_script&); + + void visit_octave_user_function (octave_user_function&); + + void visit_octave_user_function_header (octave_user_function&); + + void visit_octave_user_function_trailer (octave_user_function&); + + void visit_function_def (tree_function_def&); + + void visit_identifier (tree_identifier&); + + void visit_if_clause (tree_if_clause&); + + void visit_if_command (tree_if_command&); + + void visit_if_command_list (tree_if_command_list&); + + void visit_index_expression (tree_index_expression&); + + void visit_matrix (tree_matrix&); + + void visit_cell (tree_cell&); + + void visit_multi_assignment (tree_multi_assignment&); + + void visit_no_op_command (tree_no_op_command&); + + void visit_constant (tree_constant&); + + void visit_fcn_handle (tree_fcn_handle&); + + void visit_parameter_list (tree_parameter_list&); + + void visit_postfix_expression (tree_postfix_expression&); + + void visit_prefix_expression (tree_prefix_expression&); + + void visit_return_command (tree_return_command&); + + void visit_return_list (tree_return_list&); + + void visit_simple_assignment (tree_simple_assignment&); + + void visit_statement (tree_statement&); + + void visit_statement_list (tree_statement_list&); + + void visit_switch_case (tree_switch_case&); + + void visit_switch_case_list (tree_switch_case_list&); + + void visit_switch_command (tree_switch_command&); + + void visit_try_catch_command (tree_try_catch_command&); + + void do_unwind_protect_cleanup_code (tree_statement_list *list); + + void visit_unwind_protect_command (tree_unwind_protect_command&); + + void visit_while_command (tree_while_command&); + + void visit_do_until_command (tree_do_until_command&); + + void fail (void); + + typedef std::map var_map; + typedef var_map::iterator var_map_iterator; + typedef std::map finfo_map; + typedef finfo_map::iterator finfo_map_iterator; + + std::vector value_stack; + var_map variables; + finfo_map compiled_functions; + + llvm::LLVMContext &context; + llvm::Module *module; + llvm::FunctionPassManager *pass_manager; + llvm::ExecutionEngine *engine; + llvm::BasicBlock *entry_block; + + llvm::Function *print_double; +}; + +#endif diff --git a/src/pt-stmt.h b/src/pt-stmt.h --- a/src/pt-stmt.h +++ b/src/pt-stmt.h @@ -35,12 +35,13 @@ #include "base-list.h" #include "comment-list.h" #include "symtab.h" +#include "pt.h" // A statement is either a command to execute or an expression to // evaluate. class -tree_statement +tree_statement : public tree { public: diff --git a/src/symtab.h b/src/symtab.h --- a/src/symtab.h +++ b/src/symtab.h @@ -484,7 +484,7 @@ return symbol_record (rep->dup (new_scope)); } - std::string name (void) const { return rep->name; } + const std::string& name (void) const { return rep->name; } octave_value find (const octave_value_list& args = octave_value_list ()) const; diff --git a/src/toplev.cc b/src/toplev.cc --- a/src/toplev.cc +++ b/src/toplev.cc @@ -1325,6 +1325,9 @@ { false, "MAGICK_CPPFLAGS", OCTAVE_CONF_MAGICK_CPPFLAGS }, { false, "MAGICK_LDFLAGS", OCTAVE_CONF_MAGICK_LDFLAGS }, { false, "MAGICK_LIBS", OCTAVE_CONF_MAGICK_LIBS }, + { false, "LLVM_CPPFLAGS", OCTAVE_CONF_LLVM_CPPFLAGS }, + { false, "LLVM_LDFLAGS", OCTAVE_CONF_LLVM_LDFLAGS }, + { false, "LLVM_LIBS", OCTAVE_CONF_LLVM_LIBS }, { false, "MKOCTFILE_DL_LDFLAGS", OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS }, { false, "OCTAVE_LINK_DEPS", OCTAVE_CONF_OCTAVE_LINK_DEPS }, { false, "OCTAVE_LINK_OPTS", OCTAVE_CONF_OCTAVE_LINK_OPTS },