# HG changeset patch # User Max Brister # Date 1352088693 25200 # Node ID 44272909d926b77b24ab77d9a5654da90262d823 # Parent f3e339aee38f3077245ec4ea6d0d15d293fad577 Stop JIT on interrupt * jit-ir.cc (jit_call::needs_release): Move to cc file and do not release artificial assigns. (jit_error_check::variable_to_strign): New function. (jit_error_check::print): Move to cc file and improve output. * jit-ir.h (jit_call::needs_release): Move to cc file. (jit_error_check::variable): New enum. (jit_error_check::variable_to_string): New declaration. (jit_error_check::jit_error_check): Add variable argument and new overload. (jit_error_check::check_variable, jit_error_check::has_check_for): New function. (jit_error_check::check_for): Ensure has_check_for is true. (jit_error_check::print): Move to cc file. (jit_error_check::check_alive): Always true if has_check_for is false. (jit_error_check::mvariable): New variable. * jit-typeinfo.cc (jit_typeinfo::jit_typeinfo): Initialize loctave_interrupt_state and fix name of cast to any. (jit_typeinfo::do_insert_interrupt_check): New function. * jit-typeinfo.h (jit_typeinfo::insert_interrupt_check): New function. (jit_typeinfo::do_insert_interrupt_check): New declaration. (jit_typeinfo::loctave_interrupt_state): New variable. * pt-jit.cc (jit_convert::visit_simple_for_command, jit_convert::visit_while_command): Check interrupt state. (jit_convert::create_check_impl): Specify var_error_state check. (jit_convert_llvm::visit): Generate var_interrupt error check. (jit_function_info::execute, jit_info::execute): Call octave_quit. diff --git a/libinterp/interp-core/jit-ir.cc b/libinterp/interp-core/jit-ir.cc --- a/libinterp/interp-core/jit-ir.cc +++ b/libinterp/interp-core/jit-ir.cc @@ -698,6 +698,23 @@ // -------------------- 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 (use->user ()); + if (assign && assign->artificial ()) + return false; + } + + return true; + } + return false; +} + +bool jit_call::infer (void) { // FIXME: explain algorithm @@ -726,6 +743,33 @@ 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 << " " << *check_for () << ", "; + print_successor (os << " ", 1) << ", "; + return print_successor (os << " ", 0); +} + // -------------------- jit_magic_end -------------------- jit_magic_end::context::context (jit_factory& factory, jit_value *avalue, size_t aindex, size_t acount) diff --git a/libinterp/interp-core/jit-ir.h b/libinterp/interp-core/jit-ir.h --- a/libinterp/interp-core/jit-ir.h +++ b/libinterp/interp-core/jit-ir.h @@ -1176,10 +1176,7 @@ return moperation.overload (argument_types ()); } - virtual bool needs_release (void) const - { - return type () && jit_typeinfo::get_release (type ()).valid (); - } + virtual bool needs_release (void) const; virtual std::ostream& print (std::ostream& os, size_t indent = 0) const { @@ -1212,27 +1209,47 @@ jit_error_check : public jit_terminator { public: - jit_error_check (jit_call *acheck_for, jit_block *normal, jit_block *error) - : jit_terminator (2, error, normal, acheck_for) {} + // Which variable is the error check for? + enum variable + { + var_error_state, + var_interrupt + }; + + static std::string variable_to_string (variable v); + + jit_error_check (variable var, jit_call *acheck_for, jit_block *normal, + jit_block *error) + : jit_terminator (2, error, normal, acheck_for), mvariable (var) {} + + jit_error_check (variable var, jit_block *normal, jit_block *error) + : jit_terminator (2, error, normal), mvariable (var) {} + + variable check_variable (void) const { return mvariable; } + + bool has_check_for (void) const + { + return argument_count () == 3; + } jit_call *check_for (void) const { + assert (has_check_for ()); return static_cast (argument (2)); } - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent) << "error_check " << *check_for () << ", "; - print_successor (os, 1) << ", "; - return print_successor (os, 0); - } + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const; JIT_VALUE_ACCEPT; protected: virtual bool check_alive (size_t idx) const { + if (! has_check_for ()) + return true; return idx == 1 ? true : check_for ()->can_error (); } +private: + variable mvariable; }; // for now only handles the 1D case diff --git a/libinterp/interp-core/jit-typeinfo.cc b/libinterp/interp-core/jit-typeinfo.cc --- a/libinterp/interp-core/jit-typeinfo.cc +++ b/libinterp/interp-core/jit-typeinfo.cc @@ -1110,6 +1110,15 @@ engine->addGlobalMapping (lerror_state, reinterpret_cast (&error_state)); + // sig_atomic_type is going to be some sort of integer + sig_atomic_type = llvm::Type::getIntNTy (context, sizeof(sig_atomic_t) * 8); + loctave_interrupt_state + = new llvm::GlobalVariable (*module, sig_atomic_type, false, + llvm::GlobalValue::ExternalLinkage, 0, + "octave_interrupt_state"); + engine->addGlobalMapping (loctave_interrupt_state, + reinterpret_cast (&octave_interrupt_state)); + // generic call function { jit_type *int_t = intN (sizeof (octave_builtin::fcn) * 8); @@ -1799,7 +1808,7 @@ casts[scalar->type_id ()].stash_name ("(scalar)"); casts[complex->type_id ()].stash_name ("(complex)"); casts[matrix->type_id ()].stash_name ("(matrix)"); - casts[any->type_id ()].stash_name ("(range)"); + casts[range->type_id ()].stash_name ("(range)"); // cast any <- matrix fn = create_function (jit_convention::external, "octave_jit_cast_any_matrix", @@ -2078,6 +2087,14 @@ return abuilder.CreateLoad (lerror_state); } +llvm::Value * +jit_typeinfo::do_insert_interrupt_check (llvm::IRBuilderD& abuilder) +{ + llvm::LoadInst *val = abuilder.CreateLoad (loctave_interrupt_state); + val->setVolatile (true); + return abuilder.CreateICmpSGT (val, abuilder.getInt32 (0)); +} + void jit_typeinfo::add_builtin (const std::string& name) { diff --git a/libinterp/interp-core/jit-typeinfo.h b/libinterp/interp-core/jit-typeinfo.h --- a/libinterp/interp-core/jit-typeinfo.h +++ b/libinterp/interp-core/jit-typeinfo.h @@ -566,6 +566,11 @@ return instance->do_insert_error_check (bld); } + static llvm::Value *insert_interrupt_check (llvm::IRBuilderD& bld) + { + return instance->do_insert_interrupt_check (bld); + } + static const jit_operation& end (void) { return instance->end_fn; @@ -692,6 +697,8 @@ llvm::Value *do_insert_error_check (llvm::IRBuilderD& bld); + llvm::Value *do_insert_interrupt_check (llvm::IRBuilderD& bld); + void add_builtin (const std::string& name); void register_intrinsic (const std::string& name, size_t id, @@ -747,6 +754,9 @@ int next_id; llvm::GlobalVariable *lerror_state; + llvm::GlobalVariable *loctave_interrupt_state; + + llvm::Type *sig_atomic_type; std::vector id_to_type; jit_type *any; diff --git a/libinterp/interp-core/pt-jit.cc b/libinterp/interp-core/pt-jit.cc --- a/libinterp/interp-core/pt-jit.cc +++ b/libinterp/interp-core/pt-jit.cc @@ -403,6 +403,9 @@ jit_block *check_block = factory.create ("for_check"); blocks.push_back (check_block); + jit_block *interrupt_check = factory.create ("for_interrupt"); + blocks.push_back (interrupt_check); + if (! all_breaking) block->append (factory.create (check_block)); finish_breaks (check_block, continues); @@ -415,7 +418,14 @@ block->append (factory.create (iterator, iter_inc)); check = block->append (factory.create (jit_typeinfo::for_check, control, iterator)); - block->append (factory.create (check, body, tail)); + block->append (factory.create (check, interrupt_check, + tail)); + + block = interrupt_check; + jit_error_check *ec + = factory.create (jit_error_check::var_interrupt, + body, final_block); + block->append (ec); // breaks will go to our tail blocks.push_back (tail); @@ -834,10 +844,22 @@ } finish_breaks (tail, breaks); - finish_breaks (cond_check, continues); - - if (! all_breaking) - block->append (factory.create (cond_check)); + + if (! all_breaking || continues.size ()) + { + jit_block *interrupt_check + = factory.create ("interrupt_check"); + blocks.push_back (interrupt_check); + finish_breaks (interrupt_check, continues); + if (! all_breaking) + block->append (factory.create (interrupt_check)); + + block = interrupt_check; + jit_error_check *ec + = factory.create (jit_error_check::var_interrupt, + cond_check, final_block); + block->append (ec); + } blocks.push_back (tail); block = tail; @@ -871,8 +893,9 @@ block->append (ret); jit_block *normal = factory.create (block->name ()); - jit_error_check *check = factory.create (ret, normal, - final_block); + jit_error_check *check + = factory.create (jit_error_check::var_error_state, ret, + normal, final_block); block->append (check); blocks.push_back (normal); block = normal; @@ -1365,7 +1388,20 @@ void jit_convert_llvm::visit (jit_error_check& check) { - llvm::Value *cond = jit_typeinfo::insert_error_check (builder); + llvm::Value *cond; + + switch (check.check_variable ()) + { + case jit_error_check::var_error_state: + cond = jit_typeinfo::insert_error_check (builder); + break; + case jit_error_check::var_interrupt: + cond = jit_typeinfo::insert_interrupt_check (builder); + break; + default: + panic_impossible (); + } + llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0), check.successor_llvm (1)); check.stash_llvm (br); @@ -2080,6 +2116,8 @@ if (ret) retval(0) = octave_value (ret); + octave_quit (); + return true; } @@ -2148,6 +2186,8 @@ symbol_table::varref (arguments[i].first) = real_arguments[i]; } + octave_quit (); + return true; }