1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2012-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #define __STDC_LIMIT_MACROS 27 #define __STDC_CONSTANT_MACROS 28 29 #if defined (HAVE_CONFIG_H) 30 # include "config.h" 31 #endif 32 33 #include <sstream> 34 #include <string> 35 36 #include "bp-table.h" 37 #include "defun.h" 38 #include "errwarn.h" 39 #include "ov.h" 40 #include "pager.h" 41 #include "pt-all.h" 42 #include "pt-jit.h" 43 #include "sighandlers.h" 44 #include "symtab.h" 45 #include "variables.h" 46 #include "interpreter-private.h" 47 48 // Programming Note: As of hg id 2b2c8ac44cd2, this file builds with 49 // LLVM 3.8 but not with 3.9 (or probably any later version). 50 51 #if defined (HAVE_LLVM) 52 53 #include <llvm/Analysis/CallGraph.h> 54 #include <llvm/Analysis/Passes.h> 55 56 #if defined (HAVE_LLVM_IR_VERIFIER_H) 57 # include <llvm/IR/Verifier.h> 58 #else 59 # include <llvm/Analysis/Verifier.h> 60 #endif 61 62 #if defined (HAVE_LLVM_ANALYSIS_BASICALIASANALYSIS_H) 63 // In LLVM 3.8.x and later, we use createBasicAAWrapperPass from: 64 # include <llvm/Analysis/BasicAliasAnalysis.h> 65 #endif 66 // In LLVM 3.7.x and earlier, we use createBasicAliasAnalysisPass 67 // from llvm/Analysis/Passes.h (already included above) 68 69 #if defined (HAVE_LLVM_BITCODE_READERWRITER_H) 70 // In LLVM <= 3.9, only one header for bitcode read/writer 71 # include <llvm/Bitcode/ReaderWriter.h> 72 #else 73 // Starting with LLVM 4.0, two separate headers 74 # include <llvm/Bitcode/BitcodeReader.h> 75 # include <llvm/Bitcode/BitcodeWriter.h> 76 #endif 77 78 #include <llvm/ExecutionEngine/ExecutionEngine.h> 79 // old JIT, LLVM < 3.6.0 80 // #include <llvm/ExecutionEngine/JIT.h> 81 // MCJIT, LLVM >= 3.0.0 82 #include <llvm/ExecutionEngine/MCJIT.h> 83 #include "llvm/ExecutionEngine/SectionMemoryManager.h" 84 85 #if defined (LEGACY_PASSMANAGER) 86 # include <llvm/IR/LegacyPassManager.h> 87 #else 88 # include <llvm/PassManager.h> 89 #endif 90 91 #if defined (HAVE_LLVM_IR_FUNCTION_H) 92 # include <llvm/IR/LLVMContext.h> 93 # include <llvm/IR/Module.h> 94 # include <llvm/IR/Intrinsics.h> 95 #else 96 # include <llvm/LLVMContext.h> 97 # include <llvm/Module.h> 98 # include <llvm/Intrinsics.h> 99 #endif 100 101 #if defined (HAVE_LLVM_SUPPORT_IRBUILDER_H) 102 # include <llvm/Support/IRBuilder.h> 103 #elif defined(HAVE_LLVM_IR_IRBUILDER_H) 104 # include <llvm/IR/IRBuilder.h> 105 #else 106 # include <llvm/IRBuilder.h> 107 #endif 108 109 #include <llvm/Support/raw_os_ostream.h> 110 #include <llvm/Support/TargetSelect.h> 111 112 #if defined (HAVE_LLVM_IR_DATALAYOUT_H) 113 # include <llvm/IR/DataLayout.h> 114 #elif defined(HAVE_LLVM_DATALAYOUT_H) 115 # include <llvm/DataLayout.h> 116 #else 117 # include <llvm/Target/TargetData.h> 118 #endif 119 120 #include <llvm/Transforms/IPO.h> 121 #include <llvm/Transforms/Scalar.h> 122 123 // Starting with LLVM 3.9.0, llvm::createGVNPass has 124 // been moved to a new header file named GVN.h 125 // (before that it was in llvm/Transforms/Scalar.h) 126 #if defined (HAVE_LLVM_TRANSFORMS_SCALAR_GVN_H) 127 # include <llvm/Transforms/Scalar/GVN.h> 128 #endif 129 130 static bool Vdebug_jit = false; 131 132 static bool Vjit_enable = false; 133 134 static int Vjit_startcnt = 1000; 135 136 static int Vjit_failcnt = 0; 137 138 namespace octave 139 { 140 namespace jit 141 { 142 #if defined (LEGACY_PASSMANAGER) 143 typedef llvm::legacy::PassManager PassManager; 144 typedef llvm::legacy::FunctionPassManager FunctionPassManager; 145 #else 146 typedef llvm::PassManager PassManager; 147 typedef llvm::FunctionPassManager FunctionPassManager; 148 #endif 149 } 150 151 static llvm::IRBuilder<> builder (tree_jit::llvm_context); 152 153 static llvm::LLVMContext& context = tree_jit::llvm_context; 154 155 // -------------------- jit_break_exception -------------------- 156 157 // jit_break is thrown whenever a branch we are converting has only breaks or 158 // continues. This is because all code that follows a break or continue 159 // is dead. 160 class jit_break_exception : public std::exception 161 { }; 162 163 // -------------------- jit_convert -------------------- jit_convert(tree & tee,jit_type * for_bounds)164 jit_convert::jit_convert (tree& tee, jit_type *for_bounds) 165 : m_converting_function (false) 166 { 167 initialize (__get_current_scope__ ("jit_convert::jit_convert")); 168 169 if (for_bounds) 170 create_variable (next_for_bounds (false), for_bounds); 171 172 try 173 { 174 visit (tee); 175 } 176 catch (const jit_break_exception&) 177 { } 178 179 // breaks must have been handled by the top level loop 180 assert (m_breaks.empty ()); 181 assert (m_continues.empty ()); 182 183 m_block->append (m_factory.create<jit_branch> (m_final_block)); 184 m_blocks.push_back (m_final_block); 185 186 for (auto iter = m_vmap.begin (); iter != m_vmap.end (); ++iter) 187 { 188 jit_variable *var = iter->second; 189 const std::string& name = var->name (); 190 if (name.size () && name[0] != '#') 191 m_final_block->append (m_factory.create<jit_store_argument> (var)); 192 } 193 194 m_final_block->append (m_factory.create<jit_return> ()); 195 } 196 jit_convert(octave_user_function & fcn,const std::vector<jit_type * > & args)197 jit_convert::jit_convert (octave_user_function& fcn, 198 const std::vector<jit_type *>& args) 199 : m_converting_function (true) 200 { 201 initialize (fcn.scope ()); 202 203 tree_parameter_list *plist = fcn.parameter_list (); 204 tree_parameter_list *rlist = fcn.return_list (); 205 if (plist && plist->takes_varargs ()) 206 throw jit_fail_exception ("varags not supported"); 207 208 if (rlist && (rlist->size () > 1 || rlist->takes_varargs ())) 209 throw jit_fail_exception ("multiple returns not supported"); 210 211 if (plist) 212 { 213 auto piter = plist->begin (); 214 for (std::size_t i = 0; i < args.size (); ++i, ++piter) 215 { 216 if (piter == plist->end ()) 217 throw jit_fail_exception ("Too many parameter to function"); 218 219 tree_decl_elt *elt = *piter; 220 std::string name = elt->name (); 221 create_variable (name, args[i]); 222 } 223 } 224 225 jit_value *return_value = nullptr; 226 bool all_breaking = false; 227 if (fcn.is_special_expr ()) 228 { 229 tree_expression *expr = fcn.special_expr (); 230 if (expr) 231 { 232 jit_variable *retvar = get_variable ("#return"); 233 jit_value *retval = nullptr; 234 try 235 { 236 retval = visit (expr); 237 } 238 catch (const jit_break_exception&) 239 { } 240 241 if (m_breaks.size () || m_continues.size ()) 242 throw jit_fail_exception ("break/continue not supported in " 243 "anonymous functions"); 244 245 m_block->append (m_factory.create<jit_assign> (retvar, retval)); 246 return_value = retvar; 247 } 248 } 249 else 250 { 251 try 252 { 253 visit_statement_list (*fcn.body ()); 254 } 255 catch (const jit_break_exception&) 256 { 257 all_breaking = true; 258 } 259 260 // the user may use break or continue to exit the function 261 finish_breaks (m_final_block, m_continues); 262 finish_breaks (m_final_block, m_breaks); 263 } 264 265 if (! all_breaking) 266 m_block->append (m_factory.create<jit_branch> (m_final_block)); 267 268 m_blocks.push_back (m_final_block); 269 m_block = m_final_block; 270 271 if (! return_value && rlist && rlist->size () == 1) 272 { 273 tree_decl_elt *elt = rlist->front (); 274 return_value = get_variable (elt->name ()); 275 } 276 277 // FIXME: We should use live range analysis to delete variables where 278 // needed. For now we just delete everything at the end of the function. 279 for (auto iter = m_vmap.begin (); 280 iter != m_vmap.end (); 281 ++iter) 282 { 283 if (iter->second != return_value) 284 { 285 jit_call *call; 286 call = m_factory.create<jit_call> (&jit_typeinfo::destroy, 287 iter->second); 288 m_final_block->append (call); 289 } 290 } 291 292 if (return_value) 293 m_final_block->append (m_factory.create<jit_return> (return_value)); 294 else 295 m_final_block->append (m_factory.create<jit_return> ()); 296 } 297 298 void visit_anon_fcn_handle(tree_anon_fcn_handle &)299 jit_convert::visit_anon_fcn_handle (tree_anon_fcn_handle&) 300 { 301 throw jit_fail_exception ("No visit_anon_fcn_handle implementation"); 302 } 303 304 void visit_argument_list(tree_argument_list &)305 jit_convert::visit_argument_list (tree_argument_list&) 306 { 307 throw jit_fail_exception ("No visit_argument_list implementation"); 308 } 309 310 void visit_binary_expression(tree_binary_expression & be)311 jit_convert::visit_binary_expression (tree_binary_expression& be) 312 { 313 tree_expression *lhs = be.lhs (); 314 jit_value *lhsv = visit (lhs); 315 316 tree_expression *rhs = be.rhs (); 317 jit_value *rhsv = visit (rhs); 318 319 const jit_operation& fn = jit_typeinfo::binary_op (be.op_type ()); 320 m_result = create_checked (fn, lhsv, rhsv); 321 } 322 323 void visit_boolean_expression(tree_boolean_expression & be)324 jit_convert::visit_boolean_expression (tree_boolean_expression& be) 325 { 326 bool is_and = be.op_type () == tree_boolean_expression::bool_and; 327 328 std::string short_name = next_shortcircut_result (); 329 jit_variable *short_result = m_factory.create<jit_variable> (short_name); 330 m_vmap[short_name] = short_result; 331 332 jit_block *done = m_factory.create<jit_block> (m_block->name ()); 333 tree_expression *lhs = be.lhs (); 334 jit_value *lhsv = visit (lhs); 335 lhsv = create_checked (&jit_typeinfo::logically_true, lhsv); 336 337 jit_block *short_early = m_factory.create<jit_block> ("short_early"); 338 m_blocks.push_back (short_early); 339 340 jit_block *short_cont = m_factory.create<jit_block> ("short_cont"); 341 342 if (is_and) 343 m_block->append (m_factory.create<jit_cond_branch> (lhsv, short_cont, 344 short_early)); 345 else 346 m_block->append (m_factory.create<jit_cond_branch> (lhsv, short_early, 347 short_cont)); 348 349 m_block = short_early; 350 351 jit_value *early_result = m_factory.create<jit_const_bool> (! is_and); 352 m_block->append (m_factory.create<jit_assign> (short_result, early_result)); 353 m_block->append (m_factory.create<jit_branch> (done)); 354 355 m_blocks.push_back (short_cont); 356 m_block = short_cont; 357 358 tree_expression *rhs = be.rhs (); 359 jit_value *rhsv = visit (rhs); 360 rhsv = create_checked (&jit_typeinfo::logically_true, rhsv); 361 m_block->append (m_factory.create<jit_assign> (short_result, rhsv)); 362 m_block->append (m_factory.create<jit_branch> (done)); 363 364 m_blocks.push_back (done); 365 m_block = done; 366 m_result = short_result; 367 } 368 369 void visit_break_command(tree_break_command &)370 jit_convert::visit_break_command (tree_break_command&) 371 { 372 m_breaks.push_back (m_block); 373 throw jit_break_exception (); 374 } 375 376 void visit_colon_expression(tree_colon_expression & expr)377 jit_convert::visit_colon_expression (tree_colon_expression& expr) 378 { 379 // in the further we need to add support for classes and deal with rvalues 380 jit_value *base = visit (expr.base ()); 381 jit_value *limit = visit (expr.limit ()); 382 jit_value *increment; 383 tree_expression *tinc = expr.increment (); 384 385 if (tinc) 386 increment = visit (tinc); 387 else 388 increment = m_factory.create<jit_const_scalar> (1); 389 390 m_result = m_block->append (m_factory.create<jit_call> (jit_typeinfo::make_range, 391 base, limit, increment)); 392 } 393 394 void visit_continue_command(tree_continue_command &)395 jit_convert::visit_continue_command (tree_continue_command&) 396 { 397 m_continues.push_back (m_block); 398 throw jit_break_exception (); 399 } 400 401 void visit_decl_command(tree_decl_command &)402 jit_convert::visit_decl_command (tree_decl_command&) 403 { 404 throw jit_fail_exception ("No visit_decl_command implementation"); 405 } 406 407 void visit_decl_elt(tree_decl_elt &)408 jit_convert::visit_decl_elt (tree_decl_elt&) 409 { 410 throw jit_fail_exception ("No visit_decl_elt implementation"); 411 } 412 413 void visit_decl_init_list(tree_decl_init_list &)414 jit_convert::visit_decl_init_list (tree_decl_init_list&) 415 { 416 throw jit_fail_exception ("No visit_decl_init_list implementation"); 417 } 418 419 void visit_simple_for_command(tree_simple_for_command & cmd)420 jit_convert::visit_simple_for_command (tree_simple_for_command& cmd) 421 { 422 // Note we do an initial check to see if the loop will run at least once. 423 // This allows us to get better type inference bounds on variables defined 424 // and used only inside the for loop (e.g., the index variable) 425 426 // If we are a nested for loop we need to store the previous breaks 427 unwind_protect frame; 428 frame.protect_var (m_breaks); 429 frame.protect_var (m_continues); 430 m_breaks.clear (); 431 m_continues.clear (); 432 433 // Need a variable for our iterator, because it is used in multiple blocks 434 std::string iter_name = next_iterator (); 435 jit_variable *iterator = m_factory.create<jit_variable> (iter_name); 436 m_factory.create<jit_variable> (iter_name); 437 m_vmap[iter_name] = iterator; 438 439 jit_block *body = m_factory.create<jit_block> ("for_body"); 440 jit_block *tail = m_factory.create<jit_block> ("for_tail"); 441 442 // Do control expression, iter init, and condition check in prev_block 443 // (block). 444 // if we are the top level for loop, the bounds is an input argument. 445 jit_value *control = find_variable (next_for_bounds ()); 446 if (! control) 447 control = visit (cmd.control_expr ()); 448 jit_call *init_iter = m_factory.create<jit_call> (jit_typeinfo::for_init, 449 control); 450 m_block->append (init_iter); 451 m_block->append (m_factory.create<jit_assign> (iterator, init_iter)); 452 453 jit_call *check = m_factory.create<jit_call> (jit_typeinfo::for_check, 454 control, iterator); 455 m_block->append (check); 456 m_block->append (m_factory.create<jit_cond_branch> (check, body, tail)); 457 458 m_blocks.push_back (body); 459 m_block = body; 460 461 // compute the syntactical iterator 462 jit_call *idx_rhs = m_factory.create<jit_call> (jit_typeinfo::for_index, 463 control, iterator); 464 m_block->append (idx_rhs); 465 do_assign (cmd.left_hand_side (), idx_rhs); 466 467 // do loop 468 tree_statement_list *pt_body = cmd.body (); 469 bool all_breaking = false; 470 try 471 { 472 pt_body->accept (*this); 473 } 474 catch (const jit_break_exception&) 475 { 476 if (m_continues.empty ()) 477 { 478 // WTF are you doing user? Every branch was a break, why did you 479 // have a loop??? Users are silly people... 480 finish_breaks (tail, m_breaks); 481 m_blocks.push_back (tail); 482 m_block = tail; 483 return; 484 } 485 486 all_breaking = true; 487 } 488 489 // check our condition, continues jump to this block 490 jit_block *check_block = m_factory.create<jit_block> ("for_check"); 491 m_blocks.push_back (check_block); 492 493 jit_block *interrupt_check = m_factory.create<jit_block> ("for_interrupt"); 494 m_blocks.push_back (interrupt_check); 495 496 if (! all_breaking) 497 m_block->append (m_factory.create<jit_branch> (check_block)); 498 finish_breaks (check_block, m_continues); 499 500 m_block = check_block; 501 const jit_operation& add_fn = jit_typeinfo::binary_op (octave_value::op_add); 502 jit_value *one = m_factory.create<jit_const_index> (1); 503 jit_call *iter_inc = m_factory.create<jit_call> (add_fn, iterator, one); 504 m_block->append (iter_inc); 505 m_block->append (m_factory.create<jit_assign> (iterator, iter_inc)); 506 check = m_block->append (m_factory.create<jit_call> (jit_typeinfo::for_check, 507 control, iterator)); 508 m_block->append (m_factory.create<jit_cond_branch> (check, interrupt_check, 509 tail)); 510 511 m_block = interrupt_check; 512 jit_error_check *ec 513 = m_factory.create<jit_error_check> (jit_error_check::var_interrupt, 514 body, m_final_block); 515 m_block->append (ec); 516 517 // breaks will go to our tail 518 m_blocks.push_back (tail); 519 finish_breaks (tail, m_breaks); 520 m_block = tail; 521 } 522 523 void visit_complex_for_command(tree_complex_for_command &)524 jit_convert::visit_complex_for_command (tree_complex_for_command&) 525 { 526 throw jit_fail_exception ("No visit_complex_for_command implementation"); 527 } 528 529 void visit_octave_user_script(octave_user_script &)530 jit_convert::visit_octave_user_script (octave_user_script&) 531 { 532 throw jit_fail_exception ("No visit_octave_user_script implementation"); 533 } 534 535 void visit_octave_user_function(octave_user_function &)536 jit_convert::visit_octave_user_function (octave_user_function&) 537 { 538 throw jit_fail_exception ("No visit_octave_user_function implementation"); 539 } 540 541 void visit_octave_user_function_header(octave_user_function &)542 jit_convert::visit_octave_user_function_header (octave_user_function&) 543 { 544 throw jit_fail_exception ("No visit_octave_user_function_header implementation"); 545 } 546 547 void visit_octave_user_function_trailer(octave_user_function &)548 jit_convert::visit_octave_user_function_trailer (octave_user_function&) 549 { 550 throw jit_fail_exception ("No visit_octave_user_function_trailer implementation"); 551 } 552 553 void visit_function_def(tree_function_def &)554 jit_convert::visit_function_def (tree_function_def&) 555 { 556 throw jit_fail_exception ("No visit_function_def implementation"); 557 } 558 559 void visit_identifier(tree_identifier & ti)560 jit_convert::visit_identifier (tree_identifier& ti) 561 { 562 if (ti.has_magic_end ()) 563 { 564 if (! m_end_context.size ()) 565 throw jit_fail_exception ("Illegal end"); 566 m_result = m_block->append (m_factory.create<jit_magic_end> (m_end_context)); 567 } 568 else 569 { 570 jit_variable *var = get_variable (ti.name ()); 571 jit_instruction *instr; 572 instr = m_factory.create<jit_call> (&jit_typeinfo::grab, var); 573 m_result = m_block->append (instr); 574 } 575 } 576 577 void visit_if_clause(tree_if_clause &)578 jit_convert::visit_if_clause (tree_if_clause&) 579 { 580 throw jit_fail_exception ("No visit_if_clause implementation"); 581 } 582 583 void visit_if_command_list(tree_if_command_list & lst)584 jit_convert::visit_if_command_list (tree_if_command_list& lst) 585 { 586 tree_if_clause *last = lst.back (); 587 std::size_t last_else = static_cast<std::size_t> (last->is_else_clause ()); 588 589 // entry_blocks represents the block you need to enter in order to execute 590 // the condition check for the ith clause. For the else, it is simple the 591 // else body. If there is no else body, then it is padded with the tail. 592 std::vector<jit_block *> entry_blocks (lst.size () + 1 - last_else); 593 entry_blocks[0] = m_block; 594 595 // Need to construct blocks first, because they have jumps to each other. 596 auto iter = lst.begin (); 597 ++iter; 598 for (std::size_t i = 1; iter != lst.end (); ++iter, ++i) 599 { 600 tree_if_clause *tic = *iter; 601 if (tic->is_else_clause ()) 602 entry_blocks[i] = m_factory.create<jit_block> ("else"); 603 else 604 entry_blocks[i] = m_factory.create<jit_block> ("ifelse_cond"); 605 } 606 607 jit_block *tail = m_factory.create<jit_block> ("if_tail"); 608 if (! last_else) 609 entry_blocks[entry_blocks.size () - 1] = tail; 610 611 // each branch in the if statement will have different breaks/continues 612 block_list current_breaks = m_breaks; 613 block_list current_continues = m_continues; 614 m_breaks.clear (); 615 m_continues.clear (); 616 617 std::size_t num_incoming = 0; // number of incoming blocks to our tail 618 iter = lst.begin (); 619 for (std::size_t i = 0; iter != lst.end (); ++iter, ++i) 620 { 621 tree_if_clause *tic = *iter; 622 m_block = entry_blocks[i]; 623 assert (m_block); 624 625 if (i) // the first block is prev_block, so it has already been added 626 m_blocks.push_back (entry_blocks[i]); 627 628 if (! tic->is_else_clause ()) 629 { 630 tree_expression *expr = tic->condition (); 631 jit_value *cond = visit (expr); 632 jit_call *check = create_checked (&jit_typeinfo::logically_true, 633 cond); 634 jit_block *body = m_factory.create<jit_block> (i == 0 ? "if_body" 635 : "ifelse_body"); 636 m_blocks.push_back (body); 637 638 jit_instruction *br = m_factory.create<jit_cond_branch> (check, 639 body, 640 entry_blocks[i + 1]); 641 m_block->append (br); 642 m_block = body; 643 } 644 645 tree_statement_list *stmt_lst = tic->commands (); 646 assert (stmt_lst); // jwe: Can this be null? 647 648 try 649 { 650 stmt_lst->accept (*this); 651 ++num_incoming; 652 m_block->append (m_factory.create<jit_branch> (tail)); 653 } 654 catch (const jit_break_exception&) 655 { } 656 657 current_breaks.splice (current_breaks.end (), m_breaks); 658 current_continues.splice (current_continues.end (), m_continues); 659 } 660 661 m_breaks.splice (m_breaks.end (), current_breaks); 662 m_continues.splice (m_continues.end (), current_continues); 663 664 if (num_incoming || ! last_else) 665 { 666 m_blocks.push_back (tail); 667 m_block = tail; 668 } 669 else 670 // every branch broke, so we don't have a tail 671 throw jit_break_exception (); 672 } 673 674 void visit_index_expression(tree_index_expression & exp)675 jit_convert::visit_index_expression (tree_index_expression& exp) 676 { 677 m_result = resolve (exp); 678 } 679 680 void visit_matrix(tree_matrix &)681 jit_convert::visit_matrix (tree_matrix&) 682 { 683 throw jit_fail_exception ("No visit_matrix implementation"); 684 } 685 686 void visit_cell(tree_cell &)687 jit_convert::visit_cell (tree_cell&) 688 { 689 throw jit_fail_exception ("No visit_cell implementation"); 690 } 691 692 void visit_multi_assignment(tree_multi_assignment &)693 jit_convert::visit_multi_assignment (tree_multi_assignment&) 694 { 695 throw jit_fail_exception ("No visit_multi_assignment implementation"); 696 } 697 698 void visit_no_op_command(tree_no_op_command &)699 jit_convert::visit_no_op_command (tree_no_op_command&) 700 { 701 throw jit_fail_exception ("No visit_no_op_command implementation"); 702 } 703 704 void visit_constant(tree_constant & tc)705 jit_convert::visit_constant (tree_constant& tc) 706 { 707 octave_value v = tc.value (); 708 709 jit_type *ty = jit_typeinfo::type_of (v); 710 711 if (ty == jit_typeinfo::get_scalar ()) 712 { 713 double dv = v.double_value (); 714 m_result = m_factory.create<jit_const_scalar> (dv); 715 } 716 else if (ty == jit_typeinfo::get_range ()) 717 { 718 Range rv = v.range_value (); 719 m_result = m_factory.create<jit_const_range> (rv); 720 } 721 else if (ty == jit_typeinfo::get_complex ()) 722 { 723 Complex cv = v.complex_value (); 724 m_result = m_factory.create<jit_const_complex> (cv); 725 } 726 else 727 throw jit_fail_exception ("Unknown constant"); 728 } 729 730 void visit_fcn_handle(tree_fcn_handle &)731 jit_convert::visit_fcn_handle (tree_fcn_handle&) 732 { 733 throw jit_fail_exception ("No visit_fcn_handle implementation"); 734 } 735 736 void visit_parameter_list(tree_parameter_list &)737 jit_convert::visit_parameter_list (tree_parameter_list&) 738 { 739 throw jit_fail_exception ("No visit_parameter_list implementation"); 740 } 741 742 void visit_postfix_expression(tree_postfix_expression & tpe)743 jit_convert::visit_postfix_expression (tree_postfix_expression& tpe) 744 { 745 octave_value::unary_op etype = tpe.op_type (); 746 tree_expression *operand = tpe.operand (); 747 jit_value *operandv = visit (operand); 748 749 const jit_operation& fn = jit_typeinfo::unary_op (etype); 750 m_result = create_checked (fn, operandv); 751 752 if (etype == octave_value::op_incr || etype == octave_value::op_decr) 753 { 754 jit_value *ret = create_checked (&jit_typeinfo::grab, operandv); 755 do_assign (operand, m_result); 756 m_result = ret; 757 } 758 } 759 760 void visit_prefix_expression(tree_prefix_expression & tpe)761 jit_convert::visit_prefix_expression (tree_prefix_expression& tpe) 762 { 763 octave_value::unary_op etype = tpe.op_type (); 764 tree_expression *operand = tpe.operand (); 765 const jit_operation& fn = jit_typeinfo::unary_op (etype); 766 m_result = create_checked (fn, visit (operand)); 767 768 if (etype == octave_value::op_incr || etype == octave_value::op_decr) 769 do_assign (operand, m_result); 770 } 771 772 void visit_return_command(tree_return_command &)773 jit_convert::visit_return_command (tree_return_command&) 774 { 775 throw jit_fail_exception ("No visit_return_command implementation"); 776 } 777 778 void visit_simple_assignment(tree_simple_assignment & tsa)779 jit_convert::visit_simple_assignment (tree_simple_assignment& tsa) 780 { 781 tree_expression *rhs = tsa.right_hand_side (); 782 jit_value *rhsv = visit (rhs); 783 octave_value::assign_op op = tsa.op_type (); 784 785 if (op != octave_value::op_asn_eq) 786 { 787 // Do the equivalent binary operation, then assign. 788 // This is always correct, but it isn't always optimal. 789 tree_expression *lhs = tsa.left_hand_side (); 790 jit_value *lhsv = visit (lhs); 791 octave_value::binary_op bop = octave_value::assign_op_to_binary_op (op); 792 const jit_operation& fn = jit_typeinfo::binary_op (bop); 793 rhsv = create_checked (fn, lhsv, rhsv); 794 } 795 796 m_result = do_assign (tsa.left_hand_side (), rhsv); 797 } 798 799 void visit_statement(tree_statement & stmt)800 jit_convert::visit_statement (tree_statement& stmt) 801 { 802 tree_command *cmd = stmt.command (); 803 tree_expression *expr = stmt.expression (); 804 805 if (cmd) 806 visit (cmd); 807 else 808 { 809 // stolen from tree_evaluator::visit_statement 810 bool do_bind_ans = false; 811 812 if (expr->is_identifier ()) 813 { 814 tree_identifier *id = dynamic_cast<tree_identifier *> (expr); 815 816 do_bind_ans = (! id->is_variable (m_scope.current_context ())); 817 } 818 else 819 do_bind_ans = (! expr->is_assignment_expression ()); 820 821 jit_value *expr_result = visit (expr); 822 823 if (do_bind_ans) 824 do_assign ("ans", expr_result, expr->print_result ()); 825 else if (expr->is_identifier () && expr->print_result ()) 826 { 827 // FIXME: ugly hack, we need to come up with a way to pass 828 // nargout to visit_identifier 829 const jit_operation& fn = jit_typeinfo::print_value (); 830 jit_const_string *name = m_factory.create<jit_const_string> 831 (expr->name ()); 832 m_block->append (m_factory.create<jit_call> (fn, name, 833 expr_result)); 834 } 835 } 836 } 837 838 void visit_switch_case(tree_switch_case &)839 jit_convert::visit_switch_case (tree_switch_case&) 840 { 841 throw jit_fail_exception ("No visit_switch_case implementation"); 842 } 843 844 void visit_switch_case_list(tree_switch_case_list &)845 jit_convert::visit_switch_case_list (tree_switch_case_list&) 846 { 847 throw jit_fail_exception ("No visit_switch_case_list implementation"); 848 } 849 850 void visit_switch_command(tree_switch_command & cmd)851 jit_convert::visit_switch_command (tree_switch_command& cmd) 852 { 853 tree_switch_case_list *lst = cmd.case_list (); 854 855 // always visit switch expression 856 tree_expression *expr = cmd.switch_value (); 857 assert (expr && "Switch value can not be null"); 858 jit_value *value = visit (expr); 859 assert (value); 860 861 std::size_t case_blocks_num = lst->size (); 862 863 if (! case_blocks_num) // there's nothing to do 864 return; 865 866 // check for otherwise, it's interpreted as last 'else' condition 867 std::size_t has_otherwise = 0; 868 tree_switch_case *last = lst->back (); 869 if (last->is_default_case ()) 870 has_otherwise = 1; 871 872 std::vector<jit_block *> entry_blocks (case_blocks_num+1 - has_otherwise); 873 874 // the first entry point is always the actual block. Afterward, new blocks 875 // are created for every case and the otherwise branch 876 entry_blocks[0] = m_block; 877 for (std::size_t i = 1; i < case_blocks_num; ++i) 878 entry_blocks[i] = m_factory.create<jit_block> ("case_cond"); 879 880 jit_block *tail = m_factory.create<jit_block> ("switch_tail"); 881 882 // if there's no otherwise branch, the 'else' of the last branch 883 // has to point to the tail 884 if (! has_otherwise) 885 entry_blocks[entry_blocks.size()-1] = tail; 886 887 // each branch in the case statement will have different breaks/continues 888 block_list current_breaks = m_breaks; 889 block_list current_continues = m_continues; 890 m_breaks.clear (); 891 m_continues.clear (); 892 893 std::size_t num_incoming = 0; // number of incoming blocks to our tail 894 895 auto iter = lst->begin (); 896 for (std::size_t i = 0; i < case_blocks_num; ++iter, ++i) 897 { 898 tree_switch_case *twc = *iter; 899 m_block = entry_blocks[i]; // case_cond 900 assert (m_block); 901 902 if (i) 903 m_blocks.push_back (entry_blocks[i]); // first block already pushed 904 905 if (! twc->is_default_case ()) 906 { 907 // compare result of switch expression with actual case label 908 tree_expression *te = twc->case_label (); 909 jit_value *label = visit (te); 910 assert(label); 911 912 const jit_operation& fn = jit_typeinfo::binary_op (octave_value::op_eq); 913 jit_value *cond = create_checked (fn, value, label); 914 assert(cond); 915 916 jit_call *check = create_checked (&jit_typeinfo::logically_true, 917 cond); 918 919 jit_block *body = m_factory.create<jit_block> ("case_body"); 920 m_blocks.push_back (body); 921 922 m_block->append (m_factory.create<jit_cond_branch> (check, body, 923 entry_blocks[i+1])); 924 m_block = body; // case_body 925 } 926 927 tree_statement_list *stmt_lst = twc->commands (); 928 assert(stmt_lst); 929 930 try 931 { 932 stmt_lst->accept (*this); 933 num_incoming++; 934 m_block->append (m_factory.create<jit_branch> (tail)); 935 } 936 catch (const jit_break_exception&) 937 { } 938 939 // each branch in the case statement will have different 940 // breaks/continues 941 current_breaks.splice (current_breaks.end (), m_breaks); 942 current_continues.splice (current_continues.end (), m_continues); 943 } 944 945 // each branch in the case statement will have different breaks/continues 946 m_breaks.splice (m_breaks.end (), current_breaks); 947 m_continues.splice (m_continues.end (), current_continues); 948 949 if (num_incoming || ! has_otherwise) 950 { 951 m_blocks.push_back (tail); 952 m_block = tail; // switch_tail 953 } 954 else 955 throw jit_break_exception (); // every branch broke 956 } 957 958 void visit_try_catch_command(tree_try_catch_command &)959 jit_convert::visit_try_catch_command (tree_try_catch_command&) 960 { 961 throw jit_fail_exception ("No visit_try_catch_command implementation"); 962 } 963 964 void visit_unwind_protect_command(tree_unwind_protect_command &)965 jit_convert::visit_unwind_protect_command (tree_unwind_protect_command&) 966 { 967 throw jit_fail_exception ("No visit_unwind_protect_command implementation"); 968 } 969 970 void visit_while_command(tree_while_command & wc)971 jit_convert::visit_while_command (tree_while_command& wc) 972 { 973 unwind_protect frame; 974 frame.protect_var (m_breaks); 975 frame.protect_var (m_continues); 976 m_breaks.clear (); 977 m_continues.clear (); 978 979 jit_block *cond_check = m_factory.create<jit_block> ("while_cond_check"); 980 m_block->append (m_factory.create<jit_branch> (cond_check)); 981 m_blocks.push_back (cond_check); 982 m_block = cond_check; 983 984 tree_expression *expr = wc.condition (); 985 assert (expr && "While expression can not be null"); 986 jit_value *check = visit (expr); 987 check = create_checked (&jit_typeinfo::logically_true, check); 988 989 jit_block *body = m_factory.create<jit_block> ("while_body"); 990 m_blocks.push_back (body); 991 992 jit_block *tail = m_factory.create<jit_block> ("while_tail"); 993 m_block->append (m_factory.create<jit_cond_branch> (check, body, tail)); 994 m_block = body; 995 996 tree_statement_list *loop_body = wc.body (); 997 bool all_breaking = false; 998 if (loop_body) 999 { 1000 try 1001 { 1002 loop_body->accept (*this); 1003 } 1004 catch (const jit_break_exception&) 1005 { 1006 all_breaking = true; 1007 } 1008 } 1009 1010 finish_breaks (tail, m_breaks); 1011 1012 if (! all_breaking || m_continues.size ()) 1013 { 1014 jit_block *interrupt_check 1015 = m_factory.create<jit_block> ("interrupt_check"); 1016 m_blocks.push_back (interrupt_check); 1017 finish_breaks (interrupt_check, m_continues); 1018 if (! all_breaking) 1019 m_block->append (m_factory.create<jit_branch> (interrupt_check)); 1020 1021 m_block = interrupt_check; 1022 jit_error_check *ec 1023 = m_factory.create<jit_error_check> (jit_error_check::var_interrupt, 1024 cond_check, m_final_block); 1025 m_block->append (ec); 1026 } 1027 1028 m_blocks.push_back (tail); 1029 m_block = tail; 1030 } 1031 1032 void visit_do_until_command(tree_do_until_command & duc)1033 jit_convert::visit_do_until_command (tree_do_until_command& duc) 1034 { 1035 unwind_protect frame; 1036 frame.protect_var (m_breaks); 1037 frame.protect_var (m_continues); 1038 m_breaks.clear (); 1039 m_continues.clear (); 1040 1041 jit_block *body = m_factory.create<jit_block> ("do_until_body"); 1042 jit_block *cond_check = m_factory.create<jit_block> ("do_until_cond_check"); 1043 jit_block *tail = m_factory.create<jit_block> ("do_until_tail"); 1044 1045 m_block->append (m_factory.create<jit_branch> (body)); 1046 m_blocks.push_back (body); 1047 m_block = body; 1048 1049 tree_statement_list *loop_body = duc.body (); 1050 bool all_breaking = false; 1051 if (loop_body) 1052 { 1053 try 1054 { 1055 loop_body->accept (*this); 1056 } 1057 catch (const jit_break_exception&) 1058 { 1059 all_breaking = true; 1060 } 1061 } 1062 1063 finish_breaks (tail, m_breaks); 1064 1065 if (! all_breaking || m_continues.size ()) 1066 { 1067 jit_block *interrupt_check 1068 = m_factory.create<jit_block> ("interrupt_check"); 1069 m_blocks.push_back (interrupt_check); 1070 finish_breaks (interrupt_check, m_continues); 1071 if (! all_breaking) 1072 m_block->append (m_factory.create<jit_branch> (interrupt_check)); 1073 1074 m_block = interrupt_check; 1075 jit_error_check *ec 1076 = m_factory.create<jit_error_check> (jit_error_check::var_interrupt, 1077 cond_check, m_final_block); 1078 m_block->append (ec); 1079 1080 m_blocks.push_back (cond_check); 1081 m_block = cond_check; 1082 1083 tree_expression *expr = duc.condition (); 1084 assert (expr && "Do-Until expression can not be null"); 1085 jit_value *check = visit (expr); 1086 check = create_checked (&jit_typeinfo::logically_true, check); 1087 1088 m_block->append (m_factory.create<jit_cond_branch> (check, tail, 1089 body)); 1090 } 1091 1092 m_blocks.push_back (tail); 1093 m_block = tail; 1094 } 1095 1096 void initialize(const symbol_scope & s)1097 jit_convert::initialize (const symbol_scope& s) 1098 { 1099 m_scope = s; 1100 m_iterator_count = 0; 1101 m_for_bounds_count = 0; 1102 m_short_count = 0; 1103 jit_instruction::reset_ids (); 1104 1105 m_entry_block = m_factory.create<jit_block> ("body"); 1106 m_final_block = m_factory.create<jit_block> ("final"); 1107 m_blocks.push_back (m_entry_block); 1108 m_entry_block->mark_alive (); 1109 m_block = m_entry_block; 1110 } 1111 1112 jit_call * create_checked_impl(jit_call * ret)1113 jit_convert::create_checked_impl (jit_call *ret) 1114 { 1115 m_block->append (ret); 1116 1117 jit_block *normal = m_factory.create<jit_block> (m_block->name ()); 1118 jit_error_check *check 1119 = m_factory.create<jit_error_check> (jit_error_check::var_error_state, 1120 ret, normal, m_final_block); 1121 m_block->append (check); 1122 m_blocks.push_back (normal); 1123 m_block = normal; 1124 1125 return ret; 1126 } 1127 1128 jit_variable * find_variable(const std::string & vname) const1129 jit_convert::find_variable (const std::string& vname) const 1130 { 1131 variable_map::const_iterator iter; 1132 iter = m_vmap.find (vname); 1133 return iter != m_vmap.end () ? iter->second : nullptr; 1134 } 1135 1136 jit_variable * get_variable(const std::string & vname)1137 jit_convert::get_variable (const std::string& vname) 1138 { 1139 jit_variable *ret = find_variable (vname); 1140 if (ret) 1141 return ret; 1142 1143 symbol_table& symtab = __get_symbol_table__ ("jit_convert::find_variable"); 1144 1145 symbol_record record = m_scope.find_symbol (vname); 1146 if (record.is_persistent () || record.is_global ()) 1147 throw jit_fail_exception ("Persistent and global not yet supported"); 1148 1149 if (m_converting_function) 1150 return create_variable (vname, jit_typeinfo::get_any (), false); 1151 else 1152 { 1153 octave_value val = record.varval (m_scope.current_context ()); 1154 if (val.is_undefined ()) 1155 val = symtab.find_function (vname); 1156 1157 jit_type *type = jit_typeinfo::type_of (val); 1158 m_bounds.push_back (type_bound (type, vname)); 1159 1160 return create_variable (vname, type); 1161 } 1162 } 1163 1164 jit_variable * create_variable(const std::string & vname,jit_type * type,bool isarg)1165 jit_convert::create_variable (const std::string& vname, jit_type *type, 1166 bool isarg) 1167 { 1168 jit_variable *var = m_factory.create<jit_variable> (vname); 1169 1170 if (isarg) 1171 { 1172 jit_extract_argument *extract; 1173 extract = m_factory.create<jit_extract_argument> (type, var); 1174 m_entry_block->prepend (extract); 1175 } 1176 else 1177 { 1178 jit_call *init = m_factory.create<jit_call> (&jit_typeinfo::create_undef); 1179 jit_assign *assign = m_factory.create<jit_assign> (var, init); 1180 m_entry_block->prepend (assign); 1181 m_entry_block->prepend (init); 1182 } 1183 1184 return m_vmap[vname] = var; 1185 } 1186 1187 std::string next_name(const char * prefix,std::size_t & count,bool inc)1188 jit_convert::next_name (const char *prefix, std::size_t& count, bool inc) 1189 { 1190 std::stringstream ss; 1191 ss << prefix << count; 1192 if (inc) 1193 ++count; 1194 return ss.str (); 1195 } 1196 1197 jit_instruction * resolve(tree_index_expression & exp,jit_value * extra_arg,bool lhs)1198 jit_convert::resolve (tree_index_expression& exp, jit_value *extra_arg, 1199 bool lhs) 1200 { 1201 std::string type = exp.type_tags (); 1202 if (! (type.size () == 1 && type[0] == '(')) 1203 throw jit_fail_exception ("Unsupported index operation"); 1204 1205 std::list<tree_argument_list *> args = exp.arg_lists (); 1206 if (args.size () != 1) 1207 throw jit_fail_exception ("Bad number of arguments in " 1208 "tree_index_expression"); 1209 1210 tree_argument_list *arg_list = args.front (); 1211 if (! arg_list) 1212 throw jit_fail_exception ("null argument list"); 1213 1214 if (arg_list->size () < 1) 1215 throw jit_fail_exception ("Empty arg_list"); 1216 1217 tree_expression *tree_object = exp.expression (); 1218 jit_value *object; 1219 if (lhs) 1220 { 1221 tree_identifier *id = dynamic_cast<tree_identifier *> (tree_object); 1222 if (! id) 1223 throw jit_fail_exception ("expected identifier"); 1224 object = get_variable (id->name ()); 1225 } 1226 else 1227 object = visit (tree_object); 1228 1229 std::size_t narg = arg_list->size (); 1230 auto iter = arg_list->begin (); 1231 bool have_extra = extra_arg; 1232 std::vector<jit_value *> call_args (narg + 1 + have_extra); 1233 call_args[0] = object; 1234 1235 for (std::size_t idx = 0; iter != arg_list->end (); ++idx, ++iter) 1236 { 1237 unwind_protect frame; 1238 frame.add_method (&m_end_context, 1239 &std::vector<jit_magic_end::context>::pop_back); 1240 1241 jit_magic_end::context ctx (m_factory, object, idx, narg); 1242 m_end_context.push_back (ctx); 1243 call_args[idx + 1] = visit (*iter); 1244 } 1245 1246 if (extra_arg) 1247 call_args[call_args.size () - 1] = extra_arg; 1248 1249 const jit_operation& fres = (lhs ? jit_typeinfo::paren_subsasgn () 1250 : jit_typeinfo::paren_subsref ()); 1251 1252 return create_checked (fres, call_args); 1253 } 1254 1255 jit_value * do_assign(tree_expression * exp,jit_value * rhs,bool artificial)1256 jit_convert::do_assign (tree_expression *exp, jit_value *rhs, bool 1257 artificial) 1258 { 1259 if (! exp) 1260 throw jit_fail_exception ("NULL lhs in assign"); 1261 1262 if (isa<tree_identifier> (exp)) 1263 return do_assign (exp->name (), rhs, exp->print_result (), artificial); 1264 else if (tree_index_expression *idx 1265 = dynamic_cast<tree_index_expression *> (exp)) 1266 { 1267 jit_value *new_object = resolve (*idx, rhs, true); 1268 do_assign (idx->expression (), new_object, true); 1269 1270 // FIXME: Will not work for values that must be released/grabbed 1271 return rhs; 1272 } 1273 else 1274 throw jit_fail_exception ("Unsupported assignment"); 1275 } 1276 1277 jit_value * do_assign(const std::string & lhs,jit_value * rhs,bool print,bool artificial)1278 jit_convert::do_assign (const std::string& lhs, jit_value *rhs, 1279 bool print, bool artificial) 1280 { 1281 jit_variable *var = get_variable (lhs); 1282 jit_assign *assign = m_block->append (m_factory.create<jit_assign> (var, 1283 rhs)); 1284 1285 if (artificial) 1286 assign->mark_artificial (); 1287 1288 if (print) 1289 { 1290 const jit_operation& print_fn = jit_typeinfo::print_value (); 1291 jit_const_string *name = m_factory.create<jit_const_string> (lhs); 1292 m_block->append (m_factory.create<jit_call> (print_fn, name, var)); 1293 } 1294 1295 return var; 1296 } 1297 1298 jit_value * visit(tree & tee)1299 jit_convert::visit (tree& tee) 1300 { 1301 unwind_protect frame; 1302 frame.protect_var (m_result); 1303 1304 tee.accept (*this); 1305 return m_result; 1306 } 1307 1308 void finish_breaks(jit_block * dest,const block_list & lst)1309 jit_convert::finish_breaks (jit_block *dest, const block_list& lst) 1310 { 1311 for (auto iter = lst.begin (); iter != lst.end (); ++iter) 1312 { 1313 jit_block *b = *iter; 1314 b->append (m_factory.create<jit_branch> (dest)); 1315 } 1316 } 1317 1318 // -------------------- jit_convert_llvm -------------------- 1319 llvm::Function * convert_loop(const jit_module & module,const jit_block_list & blocks,const std::list<jit_value * > & constants,const std::string & llvm_function_name)1320 jit_convert_llvm::convert_loop (const jit_module& module, 1321 const jit_block_list& blocks, 1322 const std::list<jit_value *>& constants, 1323 const std::string& llvm_function_name) 1324 { 1325 m_converting_function = false; 1326 1327 // for now just init arguments from entry, later we will have to do 1328 // something more interesting 1329 jit_block *m_entry_block = blocks.front (); 1330 for (auto iter = m_entry_block->begin (); 1331 iter != m_entry_block->end (); ++iter) 1332 if (jit_extract_argument *extract 1333 = dynamic_cast<jit_extract_argument *> (*iter)) 1334 m_argument_vec.push_back (std::make_pair (extract->name (), true)); 1335 1336 jit_type *any = jit_typeinfo::get_any (); 1337 1338 // argument is an array of octave_base_value*, or octave_base_value** 1339 llvm::Type *arg_type = any->to_llvm (); // this is octave_base_value* 1340 llvm::FunctionType *ft; 1341 ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context), 1342 arg_type->getPointerTo (), false); 1343 1344 m_function = module.create_llvm_function (ft, llvm_function_name); 1345 try 1346 { 1347 m_prelude = llvm::BasicBlock::Create (context, "prelude", m_function); 1348 builder.SetInsertPoint (m_prelude); 1349 1350 // The jitted function will have only one function argument, of 1351 // octave_base_value** type 1352 llvm::Value *arg = &*(m_function->arg_begin ()); 1353 1354 for (std::size_t i = 0; i < m_argument_vec.size (); ++i) 1355 { 1356 #if defined (LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_REQUIRES_TYPE) 1357 // LLVM >= 3.7 1358 llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg_type, arg, i); 1359 #else 1360 // LLVM <= 3.6 1361 llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg, i); 1362 #endif 1363 m_arguments[m_argument_vec[i].first] = loaded_arg; 1364 } 1365 1366 convert (blocks, constants); 1367 } 1368 catch (const jit_fail_exception& e) 1369 { 1370 m_function->eraseFromParent (); 1371 throw; 1372 } 1373 1374 return m_function; 1375 } 1376 1377 jit_function convert_function(const jit_module & module,const jit_block_list & blocks,const std::list<jit_value * > & constants,octave_user_function & fcn,const std::vector<jit_type * > & args)1378 jit_convert_llvm::convert_function (const jit_module& module, 1379 const jit_block_list& blocks, 1380 const std::list<jit_value *>& constants, 1381 octave_user_function& fcn, 1382 const std::vector<jit_type *>& args) 1383 { 1384 m_converting_function = true; 1385 1386 jit_block *m_final_block = blocks.back (); 1387 jit_return *ret = dynamic_cast<jit_return *> (m_final_block->back ()); 1388 assert (ret); 1389 1390 m_creating = jit_function (&module, jit_convention::internal, 1391 "foobar", ret->result_type (), args); 1392 m_function = m_creating.to_llvm (); 1393 1394 try 1395 { 1396 m_prelude = m_creating.new_block ("prelude"); 1397 builder.SetInsertPoint (m_prelude); 1398 1399 tree_parameter_list *plist = fcn.parameter_list (); 1400 if (plist) 1401 { 1402 auto piter = plist->begin (); 1403 auto pend = plist->end (); 1404 for (std::size_t i = 0; i < args.size () && piter != pend; ++i, ++piter) 1405 { 1406 tree_decl_elt *elt = *piter; 1407 std::string arg_name = elt->name (); 1408 m_arguments[arg_name] = m_creating.argument (builder, i); 1409 } 1410 } 1411 1412 convert (blocks, constants); 1413 } 1414 catch (const jit_fail_exception& e) 1415 { 1416 m_function->eraseFromParent (); 1417 throw; 1418 } 1419 1420 return m_creating; 1421 } 1422 1423 void convert(const jit_block_list & blocks,const std::list<jit_value * > & constants)1424 jit_convert_llvm::convert (const jit_block_list& blocks, 1425 const std::list<jit_value *>& constants) 1426 { 1427 std::list<jit_block *>::const_iterator biter; 1428 for (biter = blocks.begin (); biter != blocks.end (); ++biter) 1429 { 1430 jit_block *jblock = *biter; 1431 llvm::BasicBlock *m_block = llvm::BasicBlock::Create (context, 1432 jblock->name (), 1433 m_function); 1434 jblock->stash_llvm (m_block); 1435 } 1436 1437 jit_block *first = *blocks.begin (); 1438 builder.CreateBr (first->to_llvm ()); 1439 1440 // constants aren't in the IR, we visit those first 1441 for (auto iter = constants.begin (); iter != constants.end (); ++iter) 1442 if (! isa<jit_instruction> (*iter)) 1443 visit (*iter); 1444 1445 // convert all instructions 1446 for (biter = blocks.begin (); biter != blocks.end (); ++biter) 1447 visit (*biter); 1448 1449 // now finish phi nodes 1450 for (biter = blocks.begin (); biter != blocks.end (); ++biter) 1451 { 1452 jit_block& m_block = **biter; 1453 for (auto piter = m_block.begin (); 1454 piter != m_block.end () && isa<jit_phi> (*piter); ++piter) 1455 { 1456 jit_instruction *phi = *piter; 1457 finish_phi (static_cast<jit_phi *> (phi)); 1458 } 1459 } 1460 } 1461 1462 void finish_phi(jit_phi * phi)1463 jit_convert_llvm::finish_phi (jit_phi *phi) 1464 { 1465 llvm::PHINode *llvm_phi = phi->to_llvm (); 1466 for (std::size_t i = 0; i < phi->argument_count (); ++i) 1467 { 1468 llvm::BasicBlock *pred = phi->incoming_llvm (i); 1469 llvm_phi->addIncoming (phi->argument_llvm (i), pred); 1470 } 1471 } 1472 1473 void visit(jit_const_string & cs)1474 jit_convert_llvm::visit (jit_const_string& cs) 1475 { 1476 cs.stash_llvm (builder.CreateGlobalStringPtr (cs.value ())); 1477 } 1478 1479 void visit(jit_const_bool & cb)1480 jit_convert_llvm::visit (jit_const_bool& cb) 1481 { 1482 cb.stash_llvm (llvm::ConstantInt::get (cb.type_llvm (), cb.value ())); 1483 } 1484 1485 void visit(jit_const_scalar & cs)1486 jit_convert_llvm::visit (jit_const_scalar& cs) 1487 { 1488 cs.stash_llvm (llvm::ConstantFP::get (cs.type_llvm (), cs.value ())); 1489 } 1490 1491 void visit(jit_const_complex & cc)1492 jit_convert_llvm::visit (jit_const_complex& cc) 1493 { 1494 llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); 1495 Complex value = cc.value (); 1496 llvm::Value *real = llvm::ConstantFP::get (scalar_t, value.real ()); 1497 llvm::Value *imag = llvm::ConstantFP::get (scalar_t, value.imag ()); 1498 cc.stash_llvm (jit_typeinfo::create_complex (real, imag)); 1499 } 1500 visit(jit_const_index & ci)1501 void jit_convert_llvm::visit (jit_const_index& ci) 1502 { 1503 ci.stash_llvm (llvm::ConstantInt::get (ci.type_llvm (), ci.value ())); 1504 } 1505 1506 void visit(jit_const_range & cr)1507 jit_convert_llvm::visit (jit_const_range& cr) 1508 { 1509 llvm::StructType *stype = llvm::cast<llvm::StructType>(cr.type_llvm ()); 1510 llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); 1511 llvm::Type *idx = jit_typeinfo::get_index_llvm (); 1512 const jit_range& rng = cr.value (); 1513 1514 llvm::Constant *constants[4]; 1515 constants[0] = llvm::ConstantFP::get (scalar_t, rng.m_base); 1516 constants[1] = llvm::ConstantFP::get (scalar_t, rng.m_limit); 1517 constants[2] = llvm::ConstantFP::get (scalar_t, rng.m_inc); 1518 constants[3] = llvm::ConstantInt::get (idx, rng.m_nelem); 1519 1520 llvm::Value *as_llvm; 1521 as_llvm = llvm::ConstantStruct::get (stype, 1522 llvm::makeArrayRef (constants, 4)); 1523 cr.stash_llvm (as_llvm); 1524 } 1525 1526 void visit(jit_block & b)1527 jit_convert_llvm::visit (jit_block& b) 1528 { 1529 llvm::BasicBlock *m_block = b.to_llvm (); 1530 builder.SetInsertPoint (m_block); 1531 for (auto iter = b.begin (); iter != b.end (); ++iter) 1532 visit (*iter); 1533 } 1534 1535 void visit(jit_branch & b)1536 jit_convert_llvm::visit (jit_branch& b) 1537 { 1538 b.stash_llvm (builder.CreateBr (b.successor_llvm ())); 1539 } 1540 1541 void visit(jit_cond_branch & cb)1542 jit_convert_llvm::visit (jit_cond_branch& cb) 1543 { 1544 llvm::Value *cond = cb.cond_llvm (); 1545 llvm::Value *br; 1546 br = builder.CreateCondBr (cond, cb.successor_llvm (0), 1547 cb.successor_llvm (1)); 1548 cb.stash_llvm (br); 1549 } 1550 1551 void visit(jit_call & call)1552 jit_convert_llvm::visit (jit_call& call) 1553 { 1554 const jit_function& ol = call.overload (); 1555 1556 std::vector<jit_value *> args (call.arguments ().size ()); 1557 for (std::size_t i = 0; i < args.size (); ++i) 1558 args[i] = call.argument (i); 1559 1560 llvm::Value *ret = ol.call (builder, args); 1561 call.stash_llvm (ret); 1562 } 1563 1564 void visit(jit_extract_argument & extract)1565 jit_convert_llvm::visit (jit_extract_argument& extract) 1566 { 1567 llvm::Value *arg = m_arguments[extract.name ()]; 1568 assert (arg); 1569 1570 if (m_converting_function) 1571 extract.stash_llvm (arg); 1572 else 1573 { 1574 arg = builder.CreateLoad (arg); 1575 1576 const jit_function& ol = extract.overload (); 1577 extract.stash_llvm (ol.call (builder, arg)); 1578 } 1579 } 1580 1581 void visit(jit_store_argument & store)1582 jit_convert_llvm::visit (jit_store_argument& store) 1583 { 1584 const jit_function& ol = store.overload (); 1585 llvm::Value *arg_value = ol.call (builder, store.result ()); 1586 llvm::Value *arg = m_arguments[store.name ()]; 1587 store.stash_llvm (builder.CreateStore (arg_value, arg)); 1588 } 1589 1590 void visit(jit_return & ret)1591 jit_convert_llvm::visit (jit_return& ret) 1592 { 1593 jit_value *res = ret.result (); 1594 1595 if (m_converting_function) 1596 m_creating.do_return (builder, res->to_llvm (), false); 1597 else 1598 { 1599 if (res) 1600 builder.CreateRet (res->to_llvm ()); 1601 else 1602 builder.CreateRetVoid (); 1603 } 1604 } 1605 1606 void visit(jit_phi & phi)1607 jit_convert_llvm::visit (jit_phi& phi) 1608 { 1609 // we might not have converted all incoming branches, so we don't 1610 // set incoming branches now 1611 llvm::PHINode *node = llvm::PHINode::Create (phi.type_llvm (), 1612 phi.argument_count ()); 1613 builder.Insert (node); 1614 phi.stash_llvm (node); 1615 } 1616 1617 void visit(jit_variable &)1618 jit_convert_llvm::visit (jit_variable&) 1619 { 1620 throw jit_fail_exception ("ERROR: SSA construction should remove all variables"); 1621 } 1622 1623 void visit(jit_error_check & check)1624 jit_convert_llvm::visit (jit_error_check& check) 1625 { 1626 llvm::Value *cond; 1627 1628 switch (check.check_variable ()) 1629 { 1630 case jit_error_check::var_error_state: 1631 cond = jit_typeinfo::insert_error_check (builder); 1632 break; 1633 case jit_error_check::var_interrupt: 1634 cond = jit_typeinfo::insert_interrupt_check (builder); 1635 break; 1636 default: 1637 panic_impossible (); 1638 } 1639 1640 llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0), 1641 check.successor_llvm (1)); 1642 check.stash_llvm (br); 1643 } 1644 1645 void visit(jit_assign & assign)1646 jit_convert_llvm::visit (jit_assign& assign) 1647 { 1648 jit_value *new_value = assign.src (); 1649 assign.stash_llvm (new_value->to_llvm ()); 1650 1651 if (assign.artificial ()) 1652 return; 1653 1654 jit_value *overwrite = assign.overwrite (); 1655 if (isa<jit_assign_base> (overwrite)) 1656 { 1657 const jit_function& ol = jit_typeinfo::get_release (overwrite->type ()); 1658 if (ol.valid ()) 1659 ol.call (builder, overwrite); 1660 } 1661 } 1662 1663 void visit(jit_argument &)1664 jit_convert_llvm::visit (jit_argument&) 1665 { } 1666 1667 void visit(jit_magic_end & me)1668 jit_convert_llvm::visit (jit_magic_end& me) 1669 { 1670 const jit_function& ol = me.overload (); 1671 1672 jit_magic_end::context ctx = me.resolve_context (); 1673 llvm::Value *ret = ol.call (builder, ctx.m_value, ctx.m_index, 1674 ctx.m_count); 1675 me.stash_llvm (ret); 1676 } 1677 1678 // -------------------- jit_infer -------------------- jit_infer(jit_factory & afactory,jit_block_list & ablocks,const variable_map & avmap)1679 jit_infer::jit_infer (jit_factory& afactory, jit_block_list& ablocks, 1680 const variable_map& avmap) 1681 : m_blocks (ablocks), m_factory (afactory), m_vmap (avmap) { } 1682 1683 void infer(void)1684 jit_infer::infer (void) 1685 { 1686 construct_ssa (); 1687 1688 // initialize the worklist to instructions derived from constants 1689 const std::list<jit_value *>& constants = m_factory.constants (); 1690 for (auto iter = constants.begin (); iter != constants.end (); ++iter) 1691 append_users (*iter); 1692 1693 // the entry block terminator may be a regular branch statement 1694 if (entry_block ().terminator ()) 1695 push_worklist (entry_block ().terminator ()); 1696 1697 // FIXME: Describe algorithm here 1698 while (m_worklist.size ()) 1699 { 1700 jit_instruction *next = m_worklist.front (); 1701 m_worklist.pop_front (); 1702 next->stash_in_worklist (false); 1703 1704 if (next->infer ()) 1705 { 1706 // terminators need to be handles specially 1707 if (jit_terminator *term = dynamic_cast<jit_terminator *> (next)) 1708 append_users_term (term); 1709 else 1710 append_users (next); 1711 } 1712 } 1713 1714 remove_dead (); 1715 m_blocks.label (); 1716 place_releases (); 1717 simplify_phi (); 1718 } 1719 1720 void append_users(jit_value * v)1721 jit_infer::append_users (jit_value *v) 1722 { 1723 for (jit_use *use = v->first_use (); use; use = use->next ()) 1724 push_worklist (use->user ()); 1725 } 1726 1727 void append_users_term(jit_terminator * term)1728 jit_infer::append_users_term (jit_terminator *term) 1729 { 1730 for (std::size_t i = 0; i < term->successor_count (); ++i) 1731 { 1732 if (term->alive (i)) 1733 { 1734 jit_block *succ = term->successor (i); 1735 for (auto iter = succ->begin (); 1736 iter != succ->end () && isa<jit_phi> (*iter); ++iter) 1737 push_worklist (*iter); 1738 1739 jit_terminator *sterm = succ->terminator (); 1740 if (sterm) 1741 push_worklist (sterm); 1742 } 1743 } 1744 } 1745 1746 void construct_ssa(void)1747 jit_infer::construct_ssa (void) 1748 { 1749 m_blocks.label (); 1750 final_block ().compute_idom (entry_block ()); 1751 entry_block ().compute_df (); 1752 entry_block ().create_dom_tree (); 1753 1754 // insert phi nodes where needed, this is done on a per variable basis 1755 for (auto iter = m_vmap.cbegin (); iter != m_vmap.cend (); ++iter) 1756 { 1757 jit_block::df_set visited, added_phi; 1758 std::list<jit_block *> ssa_worklist; 1759 iter->second->use_blocks (visited); 1760 ssa_worklist.insert (ssa_worklist.begin (), visited.begin (), 1761 visited.end ()); 1762 1763 while (ssa_worklist.size ()) 1764 { 1765 jit_block *b = ssa_worklist.front (); 1766 ssa_worklist.pop_front (); 1767 1768 for (auto diter = b->df_begin (); diter != b->df_end (); ++diter) 1769 { 1770 jit_block *dblock = *diter; 1771 if (! added_phi.count (dblock)) 1772 { 1773 jit_phi *phi = m_factory.create<jit_phi> (iter->second, 1774 dblock->use_count ()); 1775 dblock->prepend (phi); 1776 added_phi.insert (dblock); 1777 } 1778 1779 if (! visited.count (dblock)) 1780 { 1781 ssa_worklist.push_back (dblock); 1782 visited.insert (dblock); 1783 } 1784 } 1785 } 1786 } 1787 1788 do_construct_ssa (entry_block (), entry_block ().visit_count ()); 1789 } 1790 1791 void do_construct_ssa(jit_block & ablock,std::size_t avisit_count)1792 jit_infer::do_construct_ssa (jit_block& ablock, std::size_t avisit_count) 1793 { 1794 if (ablock.visited (avisit_count)) 1795 return; 1796 1797 // replace variables with their current SSA value 1798 for (auto iter = ablock.begin (); iter != ablock.end (); ++iter) 1799 { 1800 jit_instruction *instr = *iter; 1801 instr->construct_ssa (); 1802 instr->push_variable (); 1803 } 1804 1805 // finish phi nodes of successors 1806 for (std::size_t i = 0; i < ablock.successor_count (); ++i) 1807 { 1808 jit_block *finish = ablock.successor (i); 1809 1810 for (auto iter = finish->begin (); 1811 iter != finish->end () && isa<jit_phi> (*iter);) 1812 { 1813 jit_phi *phi = static_cast<jit_phi *> (*iter); 1814 jit_variable *var = phi->dest (); 1815 ++iter; 1816 1817 if (var->has_top ()) 1818 phi->add_incoming (&ablock, var->top ()); 1819 else 1820 { 1821 // temporaries may have extraneous phi nodes which can be 1822 // removed 1823 assert (! phi->use_count ()); 1824 assert (var->name ().size () && var->name ()[0] == '#'); 1825 phi->remove (); 1826 } 1827 } 1828 } 1829 1830 for (std::size_t i = 0; i < ablock.dom_successor_count (); ++i) 1831 do_construct_ssa (*ablock.dom_successor (i), avisit_count); 1832 1833 ablock.pop_all (); 1834 } 1835 1836 void place_releases(void)1837 jit_infer::place_releases (void) 1838 { 1839 std::set<jit_value *> temporaries; 1840 for (auto iter = m_blocks.begin (); iter != m_blocks.end (); ++iter) 1841 { 1842 jit_block& ablock = **iter; 1843 if (ablock.id () != jit_block::NO_ID) 1844 { 1845 release_temp (ablock, temporaries); 1846 release_dead_phi (ablock); 1847 } 1848 } 1849 } 1850 1851 void push_worklist(jit_instruction * instr)1852 jit_infer::push_worklist (jit_instruction *instr) 1853 { 1854 if (! instr->in_worklist ()) 1855 { 1856 instr->stash_in_worklist (true); 1857 m_worklist.push_back (instr); 1858 } 1859 } 1860 1861 void remove_dead()1862 jit_infer::remove_dead () 1863 { 1864 jit_block_list::iterator biter; 1865 for (biter = m_blocks.begin (); biter != m_blocks.end (); ++biter) 1866 { 1867 jit_block *b = *biter; 1868 if (b->alive ()) 1869 { 1870 for (auto iter = b->begin (); 1871 iter != b->end () && isa<jit_phi> (*iter);) 1872 { 1873 jit_phi *phi = static_cast<jit_phi *> (*iter); 1874 if (phi->prune ()) 1875 iter = b->remove (iter); 1876 else 1877 ++iter; 1878 } 1879 } 1880 } 1881 1882 for (biter = m_blocks.begin (); biter != m_blocks.end ();) 1883 { 1884 jit_block *b = *biter; 1885 if (b->alive ()) 1886 { 1887 // FIXME: A special case for jit_error_check, if we generalize to 1888 // we will need to change! 1889 jit_terminator *term = b->terminator (); 1890 if (term && term->successor_count () == 2 && ! term->alive (0)) 1891 { 1892 jit_block *succ = term->successor (1); 1893 term->remove (); 1894 jit_branch *abreak = m_factory.create<jit_branch> (succ); 1895 b->append (abreak); 1896 abreak->infer (); 1897 } 1898 1899 ++biter; 1900 } 1901 else 1902 { 1903 jit_terminator *term = b->terminator (); 1904 if (term) 1905 term->remove (); 1906 biter = m_blocks.erase (biter); 1907 } 1908 } 1909 } 1910 1911 void release_dead_phi(jit_block & ablock)1912 jit_infer::release_dead_phi (jit_block& ablock) 1913 { 1914 auto iter = ablock.begin (); 1915 while (iter != ablock.end () && isa<jit_phi> (*iter)) 1916 { 1917 jit_phi *phi = static_cast<jit_phi *> (*iter); 1918 ++iter; 1919 1920 jit_use *use = phi->first_use (); 1921 if (phi->use_count () == 1 && isa<jit_assign> (use->user ())) 1922 { 1923 // instead of releasing on assign, release on all incoming 1924 // branches, this can get rid of casts inside loops 1925 for (std::size_t i = 0; i < phi->argument_count (); ++i) 1926 { 1927 jit_value *arg = phi->argument (i); 1928 if (! arg->needs_release ()) 1929 continue; 1930 1931 jit_block *inc = phi->incoming (i); 1932 jit_block *split = inc->maybe_split (m_factory, m_blocks, 1933 ablock); 1934 jit_terminator *term = split->terminator (); 1935 jit_call *release 1936 = m_factory.create<jit_call> (jit_typeinfo::release, arg); 1937 release->infer (); 1938 split->insert_before (term, release); 1939 } 1940 1941 phi->replace_with (0); 1942 phi->remove (); 1943 } 1944 } 1945 } 1946 1947 void release_temp(jit_block & ablock,std::set<jit_value * > & temp)1948 jit_infer::release_temp (jit_block& ablock, std::set<jit_value *>& temp) 1949 { 1950 for (auto iter = ablock.begin (); iter != ablock.end (); ++iter) 1951 { 1952 jit_instruction *instr = *iter; 1953 1954 // check for temporaries that require release and live across 1955 // multiple blocks 1956 if (instr->needs_release ()) 1957 { 1958 jit_block *fu_block = instr->first_use_block (); 1959 if (fu_block && fu_block != &ablock && instr->needs_release ()) 1960 temp.insert (instr); 1961 } 1962 1963 if (isa<jit_call> (instr)) 1964 { 1965 // place releases for temporary arguments 1966 for (std::size_t i = 0; i < instr->argument_count (); ++i) 1967 { 1968 jit_value *arg = instr->argument (i); 1969 if (! arg->needs_release ()) 1970 continue; 1971 1972 jit_call *release 1973 = m_factory.create<jit_call> (&jit_typeinfo::release, arg); 1974 release->infer (); 1975 ablock.insert_after (iter, release); 1976 ++iter; 1977 temp.erase (arg); 1978 } 1979 } 1980 } 1981 1982 if (! temp.size () || ! isa<jit_error_check> (ablock.terminator ())) 1983 return; 1984 1985 // FIXME: If we support try/catch or unwind_protect final_block 1986 // may not be the destination 1987 jit_block *split = ablock.maybe_split (m_factory, m_blocks, 1988 final_block ()); 1989 jit_terminator *term = split->terminator (); 1990 for (auto iter = temp.cbegin (); iter != temp.cend (); ++iter) 1991 { 1992 jit_value *value = *iter; 1993 jit_call *release 1994 = m_factory.create<jit_call> (&jit_typeinfo::release, value); 1995 split->insert_before (term, release); 1996 release->infer (); 1997 } 1998 } 1999 2000 void simplify_phi(void)2001 jit_infer::simplify_phi (void) 2002 { 2003 for (auto biter = m_blocks.begin (); biter != m_blocks.end (); ++biter) 2004 { 2005 jit_block &ablock = **biter; 2006 for (auto iter = ablock.begin (); 2007 iter != ablock.end () && isa<jit_phi> (*iter); ++iter) 2008 simplify_phi (*static_cast<jit_phi *> (*iter)); 2009 } 2010 } 2011 2012 void simplify_phi(jit_phi & phi)2013 jit_infer::simplify_phi (jit_phi& phi) 2014 { 2015 jit_block& pblock = *phi.parent (); 2016 const jit_operation& cast_fn = jit_typeinfo::cast (phi.type ()); 2017 jit_variable *dest = phi.dest (); 2018 for (std::size_t i = 0; i < phi.argument_count (); ++i) 2019 { 2020 jit_value *arg = phi.argument (i); 2021 if (arg->type () != phi.type ()) 2022 { 2023 jit_block *pred = phi.incoming (i); 2024 jit_block *split = pred->maybe_split (m_factory, m_blocks, pblock); 2025 jit_terminator *term = split->terminator (); 2026 jit_instruction *cast = m_factory.create<jit_call> (cast_fn, arg); 2027 jit_assign *assign = m_factory.create<jit_assign> (dest, cast); 2028 2029 split->insert_before (term, cast); 2030 split->insert_before (term, assign); 2031 cast->infer (); 2032 assign->infer (); 2033 phi.stash_argument (i, assign); 2034 } 2035 } 2036 } 2037 2038 2039 // ---------------- jit_memory_manager ------------------ 2040 2041 // A simple memory manager for our LLVM engines, 2042 // based on LLVM's Kaleidoscope example 2043 2044 class jit_memory_manager : public llvm::SectionMemoryManager 2045 { 2046 jit_memory_manager (const jit_memory_manager&) = delete; 2047 void operator= (const jit_memory_manager&) = delete; 2048 public: jit_memory_manager()2049 jit_memory_manager () { } ~jit_memory_manager()2050 virtual ~jit_memory_manager () { } 2051 2052 // The Kaleidoscope example in LLVM 3.8 indicates that 2053 // getPointerToNamedFunction has to be overloaded, but actually it is 2054 // getSymbolAddress that must be overloaded. 2055 virtual uint64_t getSymbolAddress (const std::string &name); 2056 2057 // Is it still useful to overload getPointerToNamedFunction to support 2058 // some older version of LLVM? Are there others virtual functions 2059 // that must be overloaded? 2060 virtual void* getPointerToNamedFunction (const std::string& name, bool 2061 abort_on_failure); 2062 }; 2063 2064 void* getPointerToNamedFunction(const std::string & name,bool abort_on_failure)2065 jit_memory_manager::getPointerToNamedFunction (const std::string& name, 2066 bool abort_on_failure) 2067 { 2068 // Try the standard symbol resolution first, but ask it not to abort 2069 void *pfn = llvm::RTDyldMemoryManager::getPointerToNamedFunction (name, 2070 false); 2071 if (pfn) 2072 return pfn; 2073 2074 pfn = tree_jit::getPointerToNamedFunction (name); 2075 if ((pfn == nullptr) && abort_on_failure) 2076 llvm::report_fatal_error ("Program used external function '" + name + 2077 "' which could not be resolved!"); 2078 return pfn; 2079 } 2080 2081 uint64_t getSymbolAddress(const std::string & name)2082 jit_memory_manager::getSymbolAddress (const std::string &name) 2083 { 2084 uint64_t addr = llvm::SectionMemoryManager::getSymbolAddress (name); 2085 if (addr) 2086 return addr; 2087 2088 addr = tree_jit::getSymbolAddress (name); 2089 if (addr == 0) 2090 llvm::report_fatal_error ("Program used extern function '" + name + 2091 "' which could not be resolved!"); 2092 2093 return addr; 2094 } 2095 2096 2097 // -------------------- tree_jit -------------------- 2098 2099 bool tree_jit::initialized = false; 2100 2101 llvm::LLVMContext tree_jit::llvm_context; 2102 2103 int tree_jit::next_forloop_number = 0; 2104 int tree_jit::next_function_number = 0; 2105 int tree_jit::next_module_number = 0; 2106 tree_jit(void)2107 tree_jit::tree_jit (void) 2108 : target_machine (nullptr) 2109 { 2110 // target_machine will be truly initialized by tree_jit::do_initialize () 2111 } 2112 ~tree_jit(void)2113 tree_jit::~tree_jit (void) 2114 { 2115 delete target_machine; 2116 } 2117 2118 tree_jit& instance(void)2119 tree_jit::instance (void) 2120 { 2121 static tree_jit ret; // singleton instance of tree_jit 2122 2123 if (! initialized) 2124 // Try to initialize the singleton instance 2125 ret.do_initialize (); 2126 2127 return ret; 2128 } 2129 2130 jit::EngineOwner create_new_engine(jit::ModuleOwner module_owner)2131 tree_jit::create_new_engine (jit::ModuleOwner module_owner) 2132 { 2133 std::string err; 2134 2135 llvm::ExecutionEngine *e = llvm::EngineBuilder (std::move (module_owner)) 2136 .setErrorStr (&err) 2137 .setMCJITMemoryManager(llvm::make_unique<jit_memory_manager> ()) 2138 .create (); 2139 2140 // Note: in some versions of LLVM, we should call .setUseMCJIT (true) 2141 // before .create () ? 2142 // FIXME: autconf this 2143 2144 if (e == nullptr) 2145 error ("failed to create JIT engine: %s", err.c_str ()); 2146 2147 return jit::EngineOwner (e); 2148 } 2149 2150 void do_register_jit_module(jit_module * jm)2151 tree_jit::do_register_jit_module (jit_module* jm) 2152 { 2153 jm_list.push_back (jm); 2154 } 2155 2156 void do_unregister_jit_module(jit_module * jm)2157 tree_jit::do_unregister_jit_module (jit_module* jm) 2158 { 2159 jm_list.remove (jm); 2160 } 2161 2162 void* do_getPointerToNamedFunction(const std::string & name) const2163 tree_jit::do_getPointerToNamedFunction (const std::string &name) const 2164 { 2165 std::list<jit_module*>::const_iterator it; 2166 2167 for (it = jm_list.begin (); it != jm_list.end (); it++) 2168 { 2169 uint64_t addr = (*it)->getFunctionAddress (name); 2170 2171 if (addr) 2172 return reinterpret_cast<void*> (addr); 2173 } 2174 2175 return nullptr; 2176 } 2177 2178 uint64_t do_getSymbolAddress(const std::string & name) const2179 tree_jit::do_getSymbolAddress(const std::string &name) const 2180 { 2181 std::list<jit_module*>::const_iterator it; 2182 2183 for (it = jm_list.begin (); it != jm_list.end (); it++) 2184 { 2185 uint64_t addr = (*it)->getFunctionAddress (name); 2186 2187 if (addr) 2188 return addr; 2189 } 2190 2191 return 0; 2192 } 2193 2194 bool do_initialize(void)2195 tree_jit::do_initialize (void) 2196 { 2197 if (initialized) 2198 return true; 2199 2200 llvm::InitializeNativeTarget (); 2201 llvm::InitializeNativeTargetAsmPrinter (); 2202 llvm::InitializeNativeTargetAsmParser (); 2203 // FIXME: Check that these three initializations succeed 2204 2205 if (target_machine == nullptr) 2206 { 2207 target_machine = llvm::EngineBuilder ().selectTarget (); 2208 if (target_machine == nullptr) 2209 return false; 2210 } 2211 2212 return (initialized = true); 2213 } 2214 2215 jit::ModuleOwner open_new_module(const std::string & module_name)2216 tree_jit::open_new_module (const std::string& module_name) 2217 { 2218 return instance ().do_open_new_module (module_name); 2219 } 2220 2221 jit::ModuleOwner do_open_new_module(const std::string & module_name) const2222 tree_jit::do_open_new_module (const std::string& module_name) const 2223 { 2224 if (! initialized) 2225 return nullptr; 2226 2227 jit::ModuleOwner m (new llvm::Module (module_name, context)); 2228 2229 2230 if (m != nullptr) 2231 m->setDataLayout (target_machine->createDataLayout ()); 2232 2233 return m; 2234 } 2235 2236 bool do_execute(tree_simple_for_command & cmd,const octave_value & bounds)2237 tree_jit::do_execute (tree_simple_for_command& cmd, 2238 const octave_value& bounds) 2239 { 2240 std::size_t tc = trip_count (bounds); 2241 if (! tc || ! initialized || ! enabled ()) 2242 return false; 2243 2244 jit_info::vmap extra_vars; 2245 extra_vars["#for_bounds0"] = &bounds; 2246 2247 jit_info *info = cmd.get_info (); 2248 2249 if (! info || ! info->match (extra_vars)) 2250 { 2251 if (tc < static_cast<std::size_t> (Vjit_startcnt)) 2252 return false; 2253 2254 delete info; 2255 2256 info = new jit_info (cmd, bounds); 2257 2258 cmd.stash_info (info); 2259 } 2260 2261 return info->execute (extra_vars); 2262 } 2263 2264 bool do_execute(tree_while_command & cmd)2265 tree_jit::do_execute (tree_while_command& cmd) 2266 { 2267 if (! initialized || ! enabled ()) 2268 return false; 2269 2270 jit_info *info = cmd.get_info (); 2271 if (! info || ! info->match ()) 2272 { 2273 delete info; 2274 info = new jit_info (cmd); 2275 cmd.stash_info (info); 2276 } 2277 2278 return info->execute (); 2279 } 2280 2281 bool do_execute(octave_user_function & fcn,const octave_value_list & args,octave_value_list & retval)2282 tree_jit::do_execute (octave_user_function& fcn, 2283 const octave_value_list& args, 2284 octave_value_list& retval) 2285 { 2286 if (! initialized || ! enabled ()) 2287 return false; 2288 2289 jit_function_info *info = fcn.get_info (); 2290 if (! info || ! info->match (args)) 2291 { 2292 delete info; 2293 info = new jit_function_info (fcn, args); 2294 fcn.stash_info (info); 2295 } 2296 2297 return info->execute (args, retval); 2298 } 2299 2300 bool enabled(void)2301 tree_jit::enabled (void) 2302 { 2303 bp_table& bptab = __get_bp_table__ ("tree_jit::enabled"); 2304 2305 // Ideally, we should only disable JIT if there is a breakpoint in the code 2306 // we are about to run. However, we can't figure this out in O(1) time, so 2307 // we conservatively check for the existence of any breakpoints. 2308 return (Vjit_enable && ! bptab.have_breakpoints () 2309 && ! Vdebug_on_interrupt && ! Vdebug_on_error); 2310 } 2311 2312 std::size_t trip_count(const octave_value & bounds) const2313 tree_jit::trip_count (const octave_value& bounds) const 2314 { 2315 if (bounds.is_range ()) 2316 { 2317 Range rng = bounds.range_value (); 2318 return rng.numel (); 2319 } 2320 2321 // unsupported type 2322 return 0; 2323 } 2324 2325 2326 // -------------------- jit_module -------------------- 2327 jit_module(const std::string & module_name)2328 jit_module::jit_module (const std::string& module_name) 2329 : m_module (nullptr), m_engine (nullptr) 2330 { 2331 jit::ModuleOwner module_owner = tree_jit::open_new_module (module_name); 2332 // FIXME: what if this fails? exception? 2333 2334 // Get a pointer to the module before ownership is transferred to engine 2335 m_module = module_owner.get (); 2336 2337 jit::EngineOwner engine_owner = std::move 2338 (tree_jit::create_new_engine (std::move (module_owner))); 2339 // FIXME: what if this fails? exception? 2340 2341 // TODO?: Consider creating the engine just before jitting 2342 2343 // We take responsibility for deleting the engine 2344 m_engine = engine_owner.get (); 2345 engine_owner.release (); 2346 2347 tree_jit::register_jit_module (this); 2348 } 2349 ~jit_module()2350 jit_module::~jit_module () 2351 { 2352 tree_jit::unregister_jit_module (this); 2353 2354 delete m_engine; 2355 } 2356 2357 // Create an LLVM function in the module, with external linkage 2358 llvm::Function* create_llvm_function(llvm::FunctionType * ftype,const llvm::Twine & name) const2359 jit_module::create_llvm_function (llvm::FunctionType *ftype, 2360 const llvm::Twine &name) const 2361 { 2362 // we mark all functinos as external linkage because this prevents 2363 // llvm from getting rid of always inline functions 2364 2365 return llvm::Function::Create (ftype, llvm::Function::ExternalLinkage, 2366 name, m_module); 2367 } 2368 2369 // Create or insert an LLVM Function declaration for an intrinsic and return 2370 // it 2371 llvm::Function* get_intrinsic_declaration(std::size_t id,std::vector<llvm::Type * > types) const2372 jit_module::get_intrinsic_declaration (std::size_t id, 2373 std::vector<llvm::Type*> types) const 2374 { 2375 return llvm::Intrinsic::getDeclaration 2376 (m_module, static_cast<llvm::Intrinsic::ID> (id), types); 2377 } 2378 2379 // Create a global in the module 2380 llvm::GlobalVariable* create_global_variable(llvm::Type * type,bool is_constant,const llvm::Twine & name) const2381 jit_module::create_global_variable (llvm::Type *type, bool is_constant, 2382 const llvm::Twine& name) const 2383 { 2384 return new llvm::GlobalVariable (*m_module, type, is_constant, 2385 llvm::GlobalValue::ExternalLinkage, 2386 nullptr, name); 2387 } 2388 2389 void do_add_global_mapping(const llvm::GlobalValue * gv,void * p) const2390 jit_module::do_add_global_mapping (const llvm::GlobalValue* gv, void* p) const 2391 { 2392 assert (gv); 2393 m_engine->addGlobalMapping (gv, p); 2394 } 2395 2396 // Return the address of the specified function. 2397 uint64_t getFunctionAddress(const std::string & name) const2398 jit_module::getFunctionAddress (const std::string &name) const 2399 { 2400 return m_engine->getFunctionAddress (name); 2401 } 2402 2403 void optimize(llvm::Function * fn) const2404 jit_module::optimize (llvm::Function *fn) const 2405 { 2406 if (Vdebug_jit) 2407 llvm::verifyModule (*m_module); 2408 2409 // DOCUMENT-ME: Why do we need two separate pass managers? 2410 2411 jit::PassManager *module_pass_manager = new jit::PassManager (); 2412 jit::FunctionPassManager *pass_manager = new jit::FunctionPassManager (m_module); 2413 2414 #if defined (LLVM_HAS_CREATEALWAYSINLINERPASS) 2415 // This pass has been removed from LLVM's C++ API after 3.9.0 2416 // FIXME: Provide a meaningful replacement instead of simply skipping it? 2417 module_pass_manager->add (llvm::createAlwaysInlinerPass ()); 2418 #endif 2419 2420 // In 3.6, a pass was inserted in the pipeline to make the DataLayout accessible: 2421 // MyPassManager->add(new DataLayoutPass(MyTargetMachine->getDataLayout())); 2422 // In 3.7, you don’t need a pass, you set the DataLayout on the Module: 2423 // MyModule->setDataLayout(MyTargetMachine->createDataLayout()); 2424 // 2425 // FIXME: autoconf to support <= 3.6 2426 // 2427 // #if defined (HAVE_LLVM_DATALAYOUT) 2428 // pass_manager->add (new llvm::DataLayout (*m_engine->getDataLayout ())); 2429 // #else 2430 // // For very old LLVM releases ??? 2431 // pass_manager->add (new llvm::TargetData (*m_engine->getTargetData ())); 2432 // #endif 2433 2434 // DOCUMENT-ME: What does each of these passes actually do? 2435 2436 pass_manager->add (llvm::createCFGSimplificationPass ()); 2437 2438 #if defined (HAVE_LLVM_ANALYSIS_BASICALIASANALYSIS_H) 2439 pass_manager->add (llvm::createBasicAAWrapperPass ()); 2440 #else 2441 pass_manager->add (llvm::createBasicAliasAnalysisPass ()); 2442 #endif 2443 2444 pass_manager->add (llvm::createPromoteMemoryToRegisterPass ()); 2445 pass_manager->add (llvm::createInstructionCombiningPass ()); 2446 pass_manager->add (llvm::createReassociatePass ()); 2447 pass_manager->add (llvm::createGVNPass ()); 2448 pass_manager->add (llvm::createCFGSimplificationPass ()); 2449 pass_manager->doInitialization (); 2450 2451 module_pass_manager->run (*m_module); 2452 pass_manager->run (*fn); 2453 2454 delete module_pass_manager; 2455 delete pass_manager; 2456 2457 if (Vdebug_jit) 2458 { 2459 // This should be OK in LLVM 3.6 -- 3.8 (and later ?) 2460 std::error_code ec; 2461 llvm::raw_fd_ostream fout ("test.bc", ec, llvm::sys::fs::F_None); 2462 2463 // std::string error; 2464 //#if defined (RAW_FD_OSTREAM_ARG_IS_LLVM_SYS_FS) 2465 // llvm::raw_fd_ostream fout ("test.bc", error, llvm::sys::fs::F_Binary); 2466 //#else 2467 // llvm::raw_fd_ostream fout ("test.bc", error, llvm::raw_fd_ostream::F_Binary); 2468 //#endif 2469 2470 llvm::WriteBitcodeToFile (m_module, fout); 2471 } 2472 } 2473 2474 void finalizeObject(void)2475 jit_module::finalizeObject (void) 2476 { 2477 m_engine->finalizeObject (); 2478 } 2479 2480 2481 // -------------------- jit_function_info -------------------- jit_function_info(octave_user_function & fcn,const octave_value_list & ov_args)2482 jit_function_info::jit_function_info (octave_user_function& fcn, 2483 const octave_value_list& ov_args) 2484 : m_llvm_function_name (""), 2485 m_function (nullptr), 2486 m_argument_types (ov_args.length ()) 2487 { 2488 std::size_t nargs = ov_args.length (); 2489 for (std::size_t i = 0; i < nargs; ++i) 2490 m_argument_types[i] = jit_typeinfo::type_of (ov_args(i)); 2491 2492 jit_function raw_fn; 2493 jit_function wrapper; 2494 2495 try 2496 { 2497 jit_convert conv (fcn, m_argument_types); 2498 jit_infer infer (conv.get_factory (), conv.get_blocks (), 2499 conv.get_variable_map ()); 2500 infer.infer (); 2501 2502 if (Vdebug_jit) 2503 { 2504 jit_block_list& blocks = infer.get_blocks (); 2505 blocks.label (); 2506 octave_stdout << "-------------------- Compiling function "; 2507 octave_stdout << "--------------------\n"; 2508 2509 tree_print_code tpc (octave_stdout); 2510 tpc.visit_octave_user_function_header (fcn); 2511 tpc.visit_statement_list (*fcn.body ()); 2512 tpc.visit_octave_user_function_trailer (fcn); 2513 blocks.print (octave_stdout, "octave jit ir"); 2514 } 2515 2516 jit_factory& factory = conv.get_factory (); 2517 jit_convert_llvm to_llvm; 2518 raw_fn = to_llvm.convert_function (*this, infer.get_blocks (), 2519 factory.constants (), fcn, 2520 m_argument_types); 2521 2522 if (Vdebug_jit) 2523 { 2524 octave_stdout << "-------------------- raw function "; 2525 octave_stdout << "--------------------\n"; 2526 octave_stdout << *raw_fn.to_llvm () << std::endl; 2527 llvm::verifyFunction (*raw_fn.to_llvm ()); 2528 } 2529 2530 m_llvm_function_name = fcn.name () + "_wrapper"; 2531 jit_type *any_t = jit_typeinfo::get_any (); 2532 std::vector<jit_type *> wrapper_args (1, jit_typeinfo::get_any_ptr ()); 2533 wrapper = jit_function (this, jit_convention::internal, 2534 m_llvm_function_name, any_t, wrapper_args); 2535 2536 llvm::BasicBlock *wrapper_body = wrapper.new_block (); 2537 builder.SetInsertPoint (wrapper_body); 2538 2539 llvm::Value *wrapper_arg = wrapper.argument (builder, 0); 2540 std::vector<llvm::Value *> raw_args (nargs); 2541 for (std::size_t i = 0; i < nargs; ++i) 2542 { 2543 llvm::Value *arg; 2544 // LLVM <= 3.6 2545 // arg = builder.CreateConstInBoundsGEP1_32 (wrapper_arg, i); 2546 // LLVM >= 3.7 2547 arg = builder.CreateConstInBoundsGEP1_32 (any_t->to_llvm (), 2548 wrapper_arg, i); 2549 2550 arg = builder.CreateLoad (arg); 2551 2552 jit_type *arg_type = m_argument_types[i]; 2553 const jit_function& cast = jit_typeinfo::cast (arg_type, any_t); 2554 raw_args[i] = cast.call (builder, arg); 2555 } 2556 2557 llvm::Value *result = raw_fn.call (builder, raw_args); 2558 if (raw_fn.result ()) 2559 { 2560 jit_type *raw_result_t = raw_fn.result (); 2561 const jit_function& cast = jit_typeinfo::cast (any_t, 2562 raw_result_t); 2563 result = cast.call (builder, result); 2564 } 2565 else 2566 { 2567 llvm::Value *zero = builder.getInt32 (0); 2568 result = builder.CreateBitCast (zero, any_t->to_llvm ()); 2569 } 2570 2571 wrapper.do_return (builder, result); 2572 2573 llvm::Function *llvm_function = wrapper.to_llvm (); 2574 optimize (llvm_function); 2575 2576 if (Vdebug_jit) 2577 { 2578 octave_stdout << "-------------------- optimized and wrapped "; 2579 octave_stdout << "--------------------\n"; 2580 octave_stdout << *llvm_function << std::endl; 2581 llvm::verifyFunction (*llvm_function); 2582 } 2583 2584 finalizeObject (); 2585 2586 uint64_t void_fn = getFunctionAddress (m_llvm_function_name); 2587 2588 if (void_fn == 0) 2589 { 2590 llvm_function->eraseFromParent (); 2591 llvm_function = nullptr; 2592 m_function = nullptr; 2593 } 2594 else 2595 { 2596 m_function = reinterpret_cast<jited_function> (void_fn); 2597 } 2598 } 2599 catch (const jit_fail_exception& e) 2600 { 2601 m_argument_types.clear (); 2602 2603 if (Vdebug_jit) 2604 { 2605 if (e.known ()) 2606 octave_stdout << "jit fail: " << e.what () << std::endl; 2607 } 2608 2609 Vjit_failcnt++; 2610 2611 wrapper.erase (); 2612 raw_fn.erase (); 2613 } 2614 } 2615 2616 bool execute(const octave_value_list & ov_args,octave_value_list & retval) const2617 jit_function_info::execute (const octave_value_list& ov_args, 2618 octave_value_list& retval) const 2619 { 2620 if (! m_function) 2621 return false; 2622 2623 // FIXME: figure out a way to delete ov_args so we avoid duplicating 2624 // refcount 2625 std::size_t nargs = ov_args.length (); 2626 std::vector<octave_base_value *> args (nargs); 2627 for (std::size_t i = 0; i < nargs; ++i) 2628 { 2629 octave_base_value *obv = ov_args(i).internal_rep (); 2630 obv->grab (); 2631 args[i] = obv; 2632 } 2633 2634 octave_base_value *ret = m_function (&args[0]); 2635 if (ret) 2636 retval(0) = octave_value (ret); 2637 2638 octave_quit (); 2639 2640 return true; 2641 } 2642 2643 bool match(const octave_value_list & ov_args) const2644 jit_function_info::match (const octave_value_list& ov_args) const 2645 { 2646 if (! m_function) 2647 return true; 2648 2649 std::size_t nargs = ov_args.length (); 2650 if (nargs != m_argument_types.size ()) 2651 return false; 2652 2653 for (std::size_t i = 0; i < nargs; ++i) 2654 if (jit_typeinfo::type_of (ov_args(i)) != m_argument_types[i]) 2655 return false; 2656 2657 return true; 2658 } 2659 2660 2661 // -------------------- jit_info -------------------- jit_info(tree & tee)2662 jit_info::jit_info (tree& tee) 2663 : m_llvm_function_name (tree_jit::generate_unique_function_name ()), 2664 m_function (nullptr) 2665 { 2666 compile (tee); 2667 } 2668 jit_info(tree & tee,const octave_value & for_bounds)2669 jit_info::jit_info (tree& tee, const octave_value& for_bounds) 2670 : m_llvm_function_name (tree_jit::generate_unique_function_name ()), 2671 m_function (nullptr) 2672 { 2673 compile (tee, jit_typeinfo::type_of (for_bounds)); 2674 } 2675 jit_info(tree_simple_for_command & tee,const octave_value & for_bounds)2676 jit_info::jit_info (tree_simple_for_command& tee, 2677 const octave_value& for_bounds) 2678 : m_llvm_function_name (tree_jit::generate_unique_forloop_name ()), 2679 m_function (nullptr) 2680 { 2681 compile (tee, jit_typeinfo::type_of (for_bounds)); 2682 } 2683 2684 bool execute(const vmap & extra_vars) const2685 jit_info::execute (const vmap& extra_vars) const 2686 { 2687 if (! m_function) 2688 return false; 2689 2690 std::vector<octave_base_value *> real_arguments (m_arguments.size ()); 2691 for (std::size_t i = 0; i < m_arguments.size (); ++i) 2692 { 2693 if (m_arguments[i].second) 2694 { 2695 octave_value current = find (extra_vars, m_arguments[i].first); 2696 octave_base_value *obv = current.internal_rep (); 2697 2698 obv->grab (); 2699 2700 real_arguments[i] = obv; 2701 } 2702 } 2703 2704 m_function (&real_arguments[0]); 2705 2706 symbol_scope scope = __require_current_scope__ ("jit_info::execute"); 2707 2708 for (std::size_t i = 0; i < m_arguments.size (); ++i) 2709 { 2710 const std::string& name = m_arguments[i].first; 2711 2712 // do not store for loop bounds temporary 2713 if (name.size () && name[0] != '#') 2714 scope.assign (m_arguments[i].first, real_arguments[i]); 2715 } 2716 2717 octave_quit (); 2718 2719 return true; 2720 } 2721 2722 bool match(const vmap & extra_vars) const2723 jit_info::match (const vmap& extra_vars) const 2724 { 2725 if (! m_function) 2726 return true; 2727 2728 for (std::size_t i = 0; i < m_bounds.size (); ++i) 2729 { 2730 const std::string& arg_name = m_bounds[i].second; 2731 octave_value value = find (extra_vars, arg_name); 2732 jit_type *type = jit_typeinfo::type_of (value); 2733 2734 // FIXME: Check for a parent relationship 2735 if (type != m_bounds[i].first) 2736 return false; 2737 } 2738 2739 return true; 2740 } 2741 2742 void compile(tree & tee,jit_type * for_bounds)2743 jit_info::compile (tree& tee, jit_type *for_bounds) 2744 { 2745 llvm::Function * llvm_function = nullptr; 2746 2747 try 2748 { 2749 jit_convert conv (tee, for_bounds); 2750 jit_infer infer (conv.get_factory (), conv.get_blocks (), 2751 conv.get_variable_map ()); 2752 2753 infer.infer (); 2754 2755 if (Vdebug_jit) 2756 { 2757 jit_block_list& blocks = infer.get_blocks (); 2758 blocks.label (); 2759 octave_stdout << "-------------------- Compiling tree --------------------\n"; 2760 octave_stdout << tee.str_print_code () << std::endl; 2761 blocks.print (octave_stdout, "octave jit ir"); 2762 } 2763 2764 jit_factory& factory = conv.get_factory (); 2765 jit_convert_llvm to_llvm; 2766 2767 llvm_function = to_llvm.convert_loop (*this, infer.get_blocks (), 2768 factory.constants (), 2769 m_llvm_function_name); 2770 2771 m_arguments = to_llvm.get_arguments (); 2772 2773 m_bounds = conv.get_bounds (); 2774 } 2775 catch (const jit_fail_exception& e) 2776 { 2777 if (Vdebug_jit) 2778 { 2779 if (e.known ()) 2780 octave_stdout << "jit fail: " << e.what () << std::endl; 2781 } 2782 2783 Vjit_failcnt++; 2784 2785 } 2786 2787 if (llvm_function) 2788 { 2789 if (Vdebug_jit) 2790 { 2791 octave_stdout << "-------------------- llvm ir --------------------"; 2792 octave_stdout << *llvm_function << std::endl; 2793 llvm::verifyFunction (*llvm_function); 2794 } 2795 2796 optimize (llvm_function); 2797 2798 if (Vdebug_jit) 2799 { 2800 octave_stdout << "-------------------- optimized llvm ir " 2801 << "--------------------\n"; 2802 octave_stdout << *llvm_function << std::endl; 2803 } 2804 2805 finalizeObject (); 2806 2807 uint64_t void_fn = getFunctionAddress (m_llvm_function_name); 2808 2809 if (void_fn == 0) 2810 { 2811 llvm_function->eraseFromParent (); 2812 llvm_function = nullptr; 2813 m_function = nullptr; 2814 } 2815 else 2816 { 2817 m_function = reinterpret_cast<jited_function> (void_fn); 2818 } 2819 } 2820 } 2821 2822 octave_value find(const vmap & extra_vars,const std::string & vname) const2823 jit_info::find (const vmap& extra_vars, const std::string& vname) const 2824 { 2825 vmap::const_iterator iter = extra_vars.find (vname); 2826 2827 if (iter == extra_vars.end ()) 2828 { 2829 symbol_scope scope = __require_current_scope__ ("jit_convert::find"); 2830 2831 return scope.varval (vname); 2832 } 2833 else 2834 return *iter->second; 2835 } 2836 } 2837 2838 #endif 2839 2840 DEFUN (jit_failcnt, args, nargout, 2841 doc: /* -*- texinfo -*- 2842 @deftypefn {} {@var{val} =} jit_failcnt () 2843 @deftypefnx {} {@var{old_val} =} jit_failcnt (@var{new_val}) 2844 @deftypefnx {} {} jit_failcnt (@var{new_val}, "local") 2845 Query or set the internal variable that counts the number of JIT fail 2846 exceptions for Octave's JIT compiler. 2847 2848 When called from inside a function with the @qcode{"local"} option, the 2849 variable is changed locally for the function and any subroutines it calls. 2850 The original variable value is restored when exiting the function. 2851 @seealso{jit_enable, jit_startcnt, debug_jit} 2852 @end deftypefn */) 2853 { 2854 #if defined (HAVE_LLVM) 2855 return SET_INTERNAL_VARIABLE (jit_failcnt); 2856 #else 2857 octave_unused_parameter (args); 2858 octave_unused_parameter (nargout); 2859 warn_disabled_feature ("jit_failcnt", "JIT compiling"); 2860 return ovl (); 2861 #endif 2862 } 2863 2864 DEFUN (debug_jit, args, nargout, 2865 doc: /* -*- texinfo -*- 2866 @deftypefn {} {@var{val} =} debug_jit () 2867 @deftypefnx {} {@var{old_val} =} debug_jit (@var{new_val}) 2868 @deftypefnx {} {} debug_jit (@var{new_val}, "local") 2869 Query or set the internal variable that determines whether 2870 debugging/tracing is enabled for Octave's JIT compiler. 2871 2872 When called from inside a function with the @qcode{"local"} option, the 2873 variable is changed locally for the function and any subroutines it calls. 2874 The original variable value is restored when exiting the function. 2875 @seealso{jit_enable, jit_startcnt} 2876 @end deftypefn */) 2877 { 2878 #if defined (HAVE_LLVM) 2879 return SET_INTERNAL_VARIABLE (debug_jit); 2880 #else 2881 octave_unused_parameter (args); 2882 octave_unused_parameter (nargout); 2883 warn_disabled_feature ("debug_jit", "JIT"); 2884 return ovl (); 2885 #endif 2886 } 2887 2888 DEFUN (jit_enable, args, nargout, 2889 doc: /* -*- texinfo -*- 2890 @deftypefn {} {@var{val} =} jit_enable () 2891 @deftypefnx {} {@var{old_val} =} jit_enable (@var{new_val}) 2892 @deftypefnx {} {} jit_enable (@var{new_val}, "local") 2893 Query or set the internal variable that enables Octave's JIT compiler. 2894 2895 When called from inside a function with the @qcode{"local"} option, the 2896 variable is changed locally for the function and any subroutines it calls. 2897 The original variable value is restored when exiting the function. 2898 @seealso{jit_startcnt, debug_jit} 2899 @end deftypefn */) 2900 { 2901 #if defined (HAVE_LLVM) 2902 return SET_INTERNAL_VARIABLE (jit_enable); 2903 #else 2904 octave_unused_parameter (args); 2905 octave_unused_parameter (nargout); 2906 warn_disabled_feature ("jit_enable", "JIT"); 2907 return ovl (); 2908 #endif 2909 } 2910 2911 DEFUN (jit_startcnt, args, nargout, 2912 doc: /* -*- texinfo -*- 2913 @deftypefn {} {@var{val} =} jit_startcnt () 2914 @deftypefnx {} {@var{old_val} =} jit_startcnt (@var{new_val}) 2915 @deftypefnx {} {} jit_startcnt (@var{new_val}, "local") 2916 Query or set the internal variable that determines whether JIT compilation 2917 will take place for a specific loop. 2918 2919 Because compilation is a costly operation it does not make sense to employ 2920 JIT when the loop count is low. By default only loops with greater than 2921 1000 iterations will be accelerated. 2922 2923 When called from inside a function with the @qcode{"local"} option, the 2924 variable is changed locally for the function and any subroutines it calls. 2925 The original variable value is restored when exiting the function. 2926 @seealso{jit_enable, jit_failcnt, debug_jit} 2927 @end deftypefn */) 2928 { 2929 #if defined (HAVE_LLVM) 2930 return SET_INTERNAL_VARIABLE_WITH_LIMITS (jit_startcnt, 1, 2931 std::numeric_limits<int>::max ()); 2932 #else 2933 octave_unused_parameter (args); 2934 octave_unused_parameter (nargout); 2935 warn_disabled_feature ("jit_startcnt", "JIT"); 2936 return ovl (); 2937 #endif 2938 } 2939