comparison libinterp/corefcn/pt-jit.cc @ 20654:b65888ec820e draft default tip gccjit

dmalcom gcc jit import
author Stefan Mahr <dac922@gmx.de>
date Fri, 27 Feb 2015 16:59:36 +0100
parents d35201e5ce5d
children
comparison
equal deleted inserted replaced
20653:9cef0a1207e4 20654:b65888ec820e
36 #include "pt-jit.h" 36 #include "pt-jit.h"
37 #include "sighandlers.h" 37 #include "sighandlers.h"
38 #include "symtab.h" 38 #include "symtab.h"
39 #include "variables.h" 39 #include "variables.h"
40 40
41 #ifdef HAVE_JIT
42
43 static bool Vdebug_jit = false;
44
45 static bool Vjit_enable = false;
46
47 static int Vjit_startcnt = 1000;
48
49 static int Vjit_failcnt = 0;
50
41 #ifdef HAVE_LLVM 51 #ifdef HAVE_LLVM
42
43 static bool Vdebug_jit = false;
44
45 static bool Vjit_enable = false;
46
47 static int Vjit_startcnt = 1000;
48
49 static int Vjit_failcnt = 0;
50
51 #include <llvm/Analysis/CallGraph.h> 52 #include <llvm/Analysis/CallGraph.h>
52 #include <llvm/Analysis/Passes.h> 53 #include <llvm/Analysis/Passes.h>
53 54
54 #ifdef HAVE_LLVM_IR_VERIFIER_H 55 #ifdef HAVE_LLVM_IR_VERIFIER_H
55 #include <llvm/IR/Verifier.h> 56 #include <llvm/IR/Verifier.h>
98 #include <llvm/Transforms/Scalar.h> 99 #include <llvm/Transforms/Scalar.h>
99 100
100 static llvm::IRBuilder<> builder (llvm::getGlobalContext ()); 101 static llvm::IRBuilder<> builder (llvm::getGlobalContext ());
101 102
102 static llvm::LLVMContext& context = llvm::getGlobalContext (); 103 static llvm::LLVMContext& context = llvm::getGlobalContext ();
104
105 #endif /* ifdef HAVE_LLVM */
103 106
104 // -------------------- jit_break_exception -------------------- 107 // -------------------- jit_break_exception --------------------
105 108
106 // jit_break is thrown whenever a branch we are converting has only breaks or 109 // jit_break is thrown whenever a branch we are converting has only breaks or
107 // continues. This is because all code that follows a break or continue is dead. 110 // continues. This is because all code that follows a break or continue is dead.
1293 jit_block *b = *iter; 1296 jit_block *b = *iter;
1294 b->append (factory.create<jit_branch> (dest)); 1297 b->append (factory.create<jit_branch> (dest));
1295 } 1298 }
1296 } 1299 }
1297 1300
1301 // -------------------- jit_convert_gcc --------------------
1302 #ifdef HAVE_GCCJIT
1303 jit_convert_gcc::jit_convert_gcc ()
1304 : m_blocks (NULL),
1305 m_constants (NULL),
1306 m_ctxt (jit_typeinfo::create_gccjit_child_context ()),
1307 m_func (),
1308 m_extracted_params (),
1309 m_block_map (),
1310 m_locals_for_insns (),
1311 m_block_stack (),
1312 m_log_visits (false)
1313 {
1314 // FIXME: error-handling
1315
1316 m_ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
1317 3);
1318
1319 // Diagnostics, debugging etc:
1320 if (1)
1321 {
1322 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO,
1323 1);
1324 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
1325 0);
1326 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
1327 1);
1328 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
1329 1);
1330 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
1331 0);
1332 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
1333 1);
1334 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
1335 0);
1336 m_ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
1337 1);
1338 }
1339 }
1340
1341 jit_convert_gcc::~jit_convert_gcc ()
1342 {
1343 m_ctxt.release ();
1344 }
1345
1346 gcc_jit_result *
1347 jit_convert_gcc::convert_loop (const jit_block_list& blocks,
1348 const std::list<jit_value *>& constants)
1349 {
1350 converting_function = false;
1351
1352 m_blocks = &blocks;
1353 m_constants = &constants;
1354
1355 jit_type *any = jit_typeinfo::get_any ();
1356 // argument is an array of octave_base_value*, or octave_base_value**
1357 gccjit::type arg_type = any->to_gccjit (); // this is octave_base_value*
1358 arg_type = arg_type.get_pointer ();
1359
1360 // for now just init arguments from entry, later we will have to do something
1361 // more interesting
1362 jit_block *entry_block = m_blocks->front ();
1363 for (jit_block::iterator iter = entry_block->begin ();
1364 iter != entry_block->end (); ++iter)
1365 if (jit_extract_argument *extract
1366 = dynamic_cast<jit_extract_argument *> (*iter))
1367 {
1368 m_argument_index[extract->name ()] = m_argument_vec.size ();
1369 m_argument_vec.push_back (std::make_pair (extract->name (), true));
1370 }
1371
1372 /* We have a single param, confusingly named "params" (an array). */
1373 params = m_ctxt.new_param (arg_type, "params");
1374
1375 std::vector<gccjit::param> params_of_fn (1, params);
1376
1377 m_func = m_ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
1378 m_ctxt.get_type (GCC_JIT_TYPE_VOID),
1379 "loop",
1380 params_of_fn,
1381 0);
1382
1383 gccjit::block initial_block = m_func.new_block ("initial");
1384
1385 /* Create gccjit::blocks for each jit_block, and for each edge.
1386
1387 We're converting from an SSA representation back to a non-SSA
1388 representation, hence we need to convert phi nodes into regular
1389 assignments. To do this, introduce a gccjit::block for each edge, to
1390 handle the phis along each edges. Jumps to blocks in the JIT-IR
1391 will become jumps to edge-handling gccjit::blocks in our CFG; each
1392 such "edge" block will end with a jump to the "real" gccjit::block. */
1393 std::list<jit_block *>::const_iterator block_iter;
1394 for (block_iter = m_blocks->begin ();
1395 block_iter != m_blocks->end ();
1396 ++block_iter)
1397 {
1398 jit_block *jblock = *block_iter;
1399
1400 // Find predecessor blocks
1401 for (jit_use *use = jblock->first_use (); use; use = use->next ())
1402 {
1403 jit_block *pred = use->user_parent ();
1404
1405 /* Create edge-handling gccjit::block. */
1406 m_blocks_for_edges[std::make_pair(pred, jblock)] =
1407 m_func.new_block (std::string ("edge_from_")
1408 + pred->name_and_id ()
1409 + std::string ("_to_")
1410 + jblock->name_and_id ());
1411 }
1412
1413 /* The "real" gccjit::block. */
1414 m_block_map[jblock] =
1415 m_func.new_block (jblock->name_and_id ());
1416 }
1417
1418 /* It's an SSA representation, so we have another pass here that
1419 creates a local for every statement. */
1420 for (block_iter = m_blocks->begin ();
1421 block_iter != m_blocks->end ();
1422 ++block_iter)
1423 for (jit_block::iterator insn_iter = (*block_iter)->begin ();
1424 insn_iter != (*block_iter)->end ();
1425 ++insn_iter)
1426 {
1427 jit_instruction *insn = *insn_iter;
1428
1429 /* Some insns have NULL type e.g. conditional branches; it only
1430 makes sense to create a local for those with actual types. */
1431 if (insn->type ())
1432 {
1433 std::stringstream ss;
1434 // FIXME: perhaps make these identifiers look less weird?
1435 // that said, the short_print vfunc conveys more information
1436 ss << "(";
1437 insn->short_print (ss);
1438 ss << ")";
1439
1440 m_locals_for_insns[insn] =
1441 m_func.new_local (insn->type_gccjit (),
1442 ss.str ().c_str ());
1443
1444 insn->stash_rvalue (m_locals_for_insns[insn]);
1445 }
1446 }
1447
1448 // constants aren't in the IR, we visit those first
1449 for (std::list<jit_value *>::const_iterator iter = m_constants->begin ();
1450 iter != m_constants->end (); ++iter)
1451 if (! isa<jit_instruction> (*iter))
1452 visit (*iter);
1453
1454 /* Prelude: extract params from the "params" array. */
1455 if (m_with_comments)
1456 initial_block.add_comment ("prelude");
1457 for (int i = 0; i < m_argument_vec.size (); ++i)
1458 {
1459 gccjit::lvalue extracted_param =
1460 m_func.new_local (any->to_gccjit (),
1461 "extracted_param_" + m_argument_vec[i].first);
1462 m_extracted_params.push_back (extracted_param);
1463 initial_block.add_assignment (
1464 extracted_param,
1465 m_ctxt.new_array_access (
1466 params,
1467 m_ctxt.new_rvalue (m_ctxt.get_type (GCC_JIT_TYPE_INT),
1468 i)));
1469 }
1470 initial_block.end_with_jump (m_block_map[*m_blocks->begin ()]);
1471
1472 // convert all instructions
1473 for (block_iter = m_blocks->begin (); block_iter != m_blocks->end (); ++block_iter)
1474 visit (**block_iter);
1475
1476 m_ctxt.dump_to_file ("/tmp/loop-dump.c", true);
1477
1478 m_func.dump_to_dot ("/tmp/loop.dot");
1479
1480 return m_ctxt.compile ();
1481 }
1482
1483 #if 0
1484 gccjit::lvalue
1485 jit_convert_gcc::as_lvalue (jit_value *jval)
1486 {
1487 if (m_log_visits)
1488 std::cerr << "jit_convert_gcc::as_lvalue (jit_value *jval): " << *jval << "\n";
1489
1490 if (!jval->has_lvalue ())
1491 {
1492 gccjit::lvalue local =
1493 m_func.new_local (/* FIXME: */
1494 m_ctxt.get_type (GCC_JIT_TYPE_INT),
1495 jval->print_string ().c_str ());
1496 jval->stash_lvalue (local);
1497 }
1498
1499 return jval->as_lvalue ();
1500 }
1501 #endif
1502
1503 gccjit::rvalue
1504 jit_convert_gcc::as_rvalue (jit_value *jval)
1505 {
1506 if (m_log_visits)
1507 std::cerr << "jit_convert_gcc::as_rvalue (jit_value *jval): " << *jval << "\n";
1508 //std::map<jit_value *, gcc_jit_rvalue *> m_rvalues;
1509
1510 if (jit_instruction *insn = dynamic_cast<jit_instruction *> (jval))
1511 {
1512 return m_locals_for_insns[insn];
1513 }
1514
1515 // return gcc_jit_lvalue_as_rvalue (as_lvalue (jval));
1516 return jval->as_rvalue ();
1517 }
1518
1519 void
1520 jit_convert_gcc::add_assignment_for_insn (jit_instruction &insn,
1521 gccjit::rvalue val)
1522 {
1523 //insn.stash_rvalue (val);
1524 if (insn.type ())
1525 get_current_block ().add_assignment (m_locals_for_insns[&insn],
1526 val);
1527 //TODO: use location of insn
1528 }
1529
1530 gccjit::block
1531 jit_convert_gcc::get_block_for_edge (jit_block *src, jit_block *dest)
1532 {
1533 return m_blocks_for_edges[std::make_pair (src, dest)];
1534 }
1535
1536 gccjit::block
1537 jit_convert_gcc::get_current_block ()
1538 {
1539 assert (!m_block_stack.empty ());
1540 return m_block_stack.top ();
1541 }
1542
1543 void
1544 jit_convert_gcc::push_block (gccjit::block block)
1545 {
1546 m_block_stack.push (block);
1547 }
1548
1549 void
1550 jit_convert_gcc::pop_block ()
1551 {
1552 m_block_stack.pop ();
1553 }
1554
1555 //std::vector<gccjit::block> m_current_block_stack;
1556
1557
1558 void
1559 jit_convert_gcc::visit (jit_const_string& cs)
1560 {
1561 if (m_log_visits)
1562 std::cerr << "jit_convert_gcc::visit (jit_const_string& cs): " << cs << "\n";
1563 gccjit::rvalue rvalue = m_ctxt.new_rvalue (cs.value ());
1564 cs.stash_rvalue (rvalue);
1565 }
1566
1567 void
1568 jit_convert_gcc::visit (jit_const_bool& cb)
1569 {
1570 if (m_log_visits)
1571 std::cerr << "jit_convert_gcc::visit (jit_const_bool& cb): " << cb << "\n";
1572 gccjit::rvalue rvalue = m_ctxt.new_rvalue (cb.type_gccjit (),
1573 cb.value ());
1574 cb.stash_rvalue (rvalue);
1575 }
1576
1577 void
1578 jit_convert_gcc::visit (jit_const_scalar& cs)
1579 {
1580 if (m_log_visits)
1581 std::cerr << "jit_convert_gcc::visit (jit_const_scalar& cs): " << cs << "\n";
1582 gccjit::rvalue rvalue = m_ctxt.new_rvalue (cs.type_gccjit (),
1583 cs.value ());
1584 cs.stash_rvalue (rvalue);
1585 }
1586
1587 void
1588 jit_convert_gcc::visit (jit_const_complex& cc)
1589 {
1590 if (m_log_visits)
1591 std::cerr << "jit_convert_gcc::visit (jit_const_complex& cc): " << cc << "\n";
1592 #if 0
1593 gccjit::rvalue rvalue = m_ctxt.new_rvalue (cc.type_gccjit (),
1594 cc.value ());
1595 cc.stash_rvalue (rvalue);
1596 #else
1597 throw jit_fail_exception ("TODO");
1598 #endif
1599 }
1600
1601 void jit_convert_gcc::visit (jit_const_index& ci)
1602 {
1603 if (m_log_visits)
1604 std::cerr << "jit_convert_gcc::visit (jit_const_index& ci): " << ci << "\n";
1605 gccjit::rvalue rvalue = m_ctxt.new_rvalue (ci.type_gccjit (),
1606 ci.value ());
1607 ci.stash_rvalue (rvalue);
1608 }
1609
1610 void
1611 jit_convert_gcc::visit (jit_const_range& cr)
1612 {
1613 if (m_log_visits)
1614 std::cerr << "jit_convert_gcc::visit (jit_const_range& cr): " << cr << "\n";
1615 #if 0
1616 gccjit::rvalue rvalue = m_ctxt.new_rvalue (cr.type_gccjit (),
1617 cr.value ());
1618 cr.stash_rvalue (rvalue);
1619 #else
1620 throw jit_fail_exception ("TODO");
1621 #endif
1622 }
1623
1624 void
1625 jit_convert_gcc::visit (jit_block& b)
1626 {
1627 /* First, handle the phi nodes by populating the edge-handling blocks
1628 with assignments that set up the phi nodes's lvalues based on the incoming
1629 edge, then jumping to the "real" block for this block. */
1630 for (jit_block::iterator insn_iter = b.begin ();
1631 insn_iter != b.end ();
1632 ++insn_iter)
1633 if (jit_phi *phi = dynamic_cast<jit_phi *> (*insn_iter))
1634 {
1635 for (size_t i = 0; i < phi->argument_count (); ++i)
1636 {
1637 jit_block *pred = phi->incomming (i);
1638 push_block (m_blocks_for_edges[std::make_pair(pred, &b)]);
1639 if (m_with_comments)
1640 {
1641 std::ostringstream os;
1642 os << "incoming edge " << i << " for: ";
1643 phi->print (os);
1644 get_current_block ().add_comment (os.str ());
1645 }
1646 get_current_block ().add_assignment (
1647 m_locals_for_insns[phi],
1648 m_locals_for_insns[static_cast <jit_instruction *> (phi->argument (i))]);
1649 pop_block ();
1650 }
1651 }
1652
1653 /* Terminate the blocks for edges leading to this block. */
1654 jit_use *use;
1655 for (use = b.first_use (); use; use = use->next ())
1656 {
1657 jit_block *pred = use->user_parent ();
1658 gccjit::block block_for_edge =
1659 m_blocks_for_edges[std::make_pair(pred, &b)];
1660 block_for_edge.end_with_jump (m_block_map[&b]);
1661 }
1662
1663 /* Now generate a block for all of the non-phi instructions. */
1664 push_block (m_block_map[&b]);
1665 for (jit_block::iterator insn_iter = b.begin ();
1666 insn_iter != b.end ();
1667 ++insn_iter)
1668 {
1669 // We've handled phi nodes above; skip them:
1670 if (dynamic_cast<jit_phi *> (*insn_iter))
1671 continue;
1672
1673 if (m_with_comments)
1674 get_current_block ().add_comment (std::string ("jit_instruction: ")
1675 + (*insn_iter)->print_string ());
1676 visit (*insn_iter);
1677 }
1678 pop_block ();
1679 }
1680
1681 void
1682 jit_convert_gcc::visit (jit_branch& b)
1683 {
1684 if (m_log_visits)
1685 std::cerr << "jit_convert_gcc::visit (jit_branch& b): " << b << "\n";
1686
1687 jit_block *this_block = b.parent ();
1688 jit_block *next = b.successor ();
1689
1690 get_current_block ().end_with_jump (get_block_for_edge (this_block, next));
1691 }
1692
1693 void
1694 jit_convert_gcc::visit (jit_cond_branch& cb)
1695 {
1696 if (m_log_visits)
1697 std::cerr << "jit_convert_gcc::visit (jit_cond_branch& cb): " << cb << "\n";
1698
1699 gccjit::rvalue boolval = as_rvalue (cb.cond ());
1700
1701 jit_block *this_block = cb.parent ();
1702 get_current_block ().end_with_conditional (
1703 boolval,
1704 get_block_for_edge (this_block, cb.successor (0)),
1705 get_block_for_edge (this_block, cb.successor (1)));
1706 }
1707
1708 void
1709 jit_convert_gcc::visit (jit_call& call)
1710 {
1711 if (m_log_visits)
1712 std::cerr << "jit_convert_gcc::visit (jit_call& call): " << call << "\n";
1713
1714 const jit_function& ol = call.overload ();
1715
1716 std::vector<jit_value *> args (call.arguments ().size ());
1717 for (size_t i = 0; i < args.size (); ++i)
1718 args[i] = call.argument (i);
1719
1720 gccjit::rvalue ret = ol.call (m_ctxt, get_current_block (), args);
1721 add_assignment_for_insn (call, ret);
1722 }
1723
1724 void
1725 jit_convert_gcc::visit (jit_extract_argument& extract)
1726 {
1727 if (m_log_visits)
1728 std::cerr << "jit_convert_gcc::visit (jit_extract_argument& extract): " << extract << "\n";
1729
1730 const std::string& argname = extract.name ();
1731
1732 // Get the stored (octave_base_value *)
1733 gccjit::lvalue param = m_extracted_params[m_argument_index[argname]];
1734
1735 // Convert it to a more specialized type:
1736 const jit_function& ol = extract.overload ();
1737 std::vector<gccjit::rvalue> args (1, param);
1738 gccjit::rvalue extracted = ol.call (m_ctxt, get_current_block (), args);
1739 add_assignment_for_insn (extract,
1740 extracted);
1741 }
1742
1743 void
1744 jit_convert_gcc::visit (jit_store_argument& store)
1745 {
1746 if (m_log_visits)
1747 std::cerr << "jit_convert_gcc::visit (jit_store_argument& store): " << store << "\n";
1748
1749 const jit_function& ol = store.overload ();
1750
1751 std::vector<jit_value *> args (1);
1752 args[0] = store.result ();
1753
1754 gccjit::rvalue ret = ol.call (m_ctxt, get_current_block (), args);
1755 int index = m_argument_index[store.name ()];
1756 get_current_block ().add_assignment (
1757 // "params[index] = ..."
1758 m_ctxt.new_array_access (
1759 params,
1760 m_ctxt.new_rvalue (m_ctxt.get_type (GCC_JIT_TYPE_INT),
1761 index)),
1762 // "... = ret;"
1763 ret);
1764 }
1765
1766 void
1767 jit_convert_gcc::visit (jit_return& ret)
1768 {
1769 if (m_log_visits)
1770 std::cerr << "jit_convert_gcc::visit (jit_return& ret): " << ret << "\n";
1771 jit_value *res = ret.result ();
1772
1773 if (converting_function)
1774 throw jit_fail_exception ("TODO");
1775 else
1776 {
1777 if (res)
1778 get_current_block ().end_with_return (res->as_rvalue ());
1779 else
1780 get_current_block ().end_with_return ();
1781 }
1782 }
1783
1784 void
1785 jit_convert_gcc::visit (jit_phi& phi)
1786 {
1787 if (m_log_visits)
1788 std::cerr << "jit_convert_gcc::visit (jit_phi& phi): " << phi << "\n";
1789 throw jit_fail_exception ("TODO");
1790 }
1791
1792 void
1793 jit_convert_gcc::visit (jit_variable& var)
1794 {
1795 if (m_log_visits)
1796 std::cerr << "jit_convert_gcc::visit (jit_variable&): " << var << "\n";
1797 throw jit_fail_exception ("TODO");
1798 }
1799
1800 void
1801 jit_convert_gcc::visit (jit_error_check& check)
1802 {
1803 if (m_log_visits)
1804 std::cerr << "jit_convert_gcc::visit (jit_error_check& check): " << check << "\n";
1805
1806 gccjit::rvalue cond;
1807
1808 switch (check.check_variable ())
1809 {
1810 case jit_error_check::var_error_state:
1811 cond = jit_typeinfo::insert_error_check (m_func);
1812 break;
1813 case jit_error_check::var_interrupt:
1814 cond = jit_typeinfo::insert_interrupt_check (m_func);
1815 break;
1816 default:
1817 panic_impossible ();
1818 }
1819
1820 jit_block *this_block = check.parent ();
1821 get_current_block ().end_with_conditional (
1822 cond,
1823 get_block_for_edge (this_block, check.successor (0)),
1824 get_block_for_edge (this_block, check.successor (1)));
1825 }
1826
1827 void
1828 jit_convert_gcc::visit (jit_assign& assign)
1829 {
1830 if (m_log_visits)
1831 std::cerr << "jit_convert_gcc::visit (jit_assign& assign): " << assign << "\n";
1832
1833 jit_value *jsrc = assign.src ();
1834
1835 add_assignment_for_insn (assign,
1836 as_rvalue (jsrc));
1837 }
1838
1839 void
1840 jit_convert_gcc::visit (jit_argument& arg)
1841 {
1842 if (m_log_visits)
1843 std::cerr << "jit_convert_gcc::visit (jit_argument&): " << arg << "\n";
1844 throw jit_fail_exception ("TODO");
1845 }
1846
1847 void
1848 jit_convert_gcc::visit (jit_magic_end& me)
1849 {
1850 if (m_log_visits)
1851 std::cerr << "jit_convert_gcc::visit (jit_magic_end& me): " << me << "\n";
1852 throw jit_fail_exception ("TODO");
1853 }
1854 #endif /* HAVE_GCCJIT */
1855
1298 // -------------------- jit_convert_llvm -------------------- 1856 // -------------------- jit_convert_llvm --------------------
1857
1858 #ifdef HAVE_LLVM
1859
1299 llvm::Function * 1860 llvm::Function *
1300 jit_convert_llvm::convert_loop (llvm::Module *module, 1861 jit_convert_llvm::convert_loop (llvm::Module *module,
1301 const jit_block_list& blocks, 1862 const jit_block_list& blocks,
1302 const std::list<jit_value *>& constants) 1863 const std::list<jit_value *>& constants)
1303 { 1864 {
1359 1920
1360 jit_block *final_block = blocks.back (); 1921 jit_block *final_block = blocks.back ();
1361 jit_return *ret = dynamic_cast<jit_return *> (final_block->back ()); 1922 jit_return *ret = dynamic_cast<jit_return *> (final_block->back ());
1362 assert (ret); 1923 assert (ret);
1363 1924
1364 creating = jit_function (module, jit_convention::internal, 1925 creating = jit_function (module,
1926 #ifdef HAVE_GCCJIT
1927 gccjit::context (), // FIXME?
1928 #endif
1929 jit_convention::internal,
1365 "foobar", ret->result_type (), args); 1930 "foobar", ret->result_type (), args);
1366 function = creating.to_llvm (); 1931 function = creating.to_llvm ();
1367 1932
1368 try 1933 try
1369 { 1934 {
1646 2211
1647 jit_magic_end::context ctx = me.resolve_context (); 2212 jit_magic_end::context ctx = me.resolve_context ();
1648 llvm::Value *ret = ol.call (builder, ctx.value, ctx.index, ctx.count); 2213 llvm::Value *ret = ol.call (builder, ctx.value, ctx.index, ctx.count);
1649 me.stash_llvm (ret); 2214 me.stash_llvm (ret);
1650 } 2215 }
2216
2217 #endif /* ifdef HAVE_LLVM */
1651 2218
1652 // -------------------- jit_infer -------------------- 2219 // -------------------- jit_infer --------------------
1653 jit_infer::jit_infer (jit_factory& afactory, jit_block_list& ablocks, 2220 jit_infer::jit_infer (jit_factory& afactory, jit_block_list& ablocks,
1654 const variable_map& avmap) 2221 const variable_map& avmap)
1655 : blocks (ablocks), factory (afactory), vmap (avmap) { } 2222 : blocks (ablocks), factory (afactory), vmap (avmap) { }
2050 } 2617 }
2051 2618
2052 bool 2619 bool
2053 tree_jit::initialize (void) 2620 tree_jit::initialize (void)
2054 { 2621 {
2622 #ifdef HAVE_LLVM
2055 if (engine) 2623 if (engine)
2056 return true; 2624 return true;
2057 2625
2058 if (! module) 2626 if (! module)
2059 { 2627 {
2087 pass_manager->add (llvm::createInstructionCombiningPass ()); 2655 pass_manager->add (llvm::createInstructionCombiningPass ());
2088 pass_manager->add (llvm::createReassociatePass ()); 2656 pass_manager->add (llvm::createReassociatePass ());
2089 pass_manager->add (llvm::createGVNPass ()); 2657 pass_manager->add (llvm::createGVNPass ());
2090 pass_manager->add (llvm::createCFGSimplificationPass ()); 2658 pass_manager->add (llvm::createCFGSimplificationPass ());
2091 pass_manager->doInitialization (); 2659 pass_manager->doInitialization ();
2092 2660 #endif /* ifdef HAVE_LLVM */
2093 jit_typeinfo::initialize (module, engine); 2661
2662 jit_typeinfo::initialize (
2663 #ifdef HAVE_LLVM
2664 module, engine
2665 #endif
2666 );
2094 2667
2095 return true; 2668 return true;
2096 } 2669 }
2097 2670
2098 bool 2671 bool
2175 2748
2176 // unsupported type 2749 // unsupported type
2177 return 0; 2750 return 0;
2178 } 2751 }
2179 2752
2180 2753 #ifdef HAVE_LLVM
2181 void 2754 void
2182 tree_jit::optimize (llvm::Function *fn) 2755 tree_jit::optimize (llvm::Function *fn)
2183 { 2756 {
2184 if (Vdebug_jit) 2757 if (Vdebug_jit)
2185 llvm::verifyModule (*module); 2758 llvm::verifyModule (*module);
2198 llvm::raw_fd_ostream::F_Binary); 2771 llvm::raw_fd_ostream::F_Binary);
2199 #endif 2772 #endif
2200 llvm::WriteBitcodeToFile (module, fout); 2773 llvm::WriteBitcodeToFile (module, fout);
2201 } 2774 }
2202 } 2775 }
2776 #endif /* ifdef HAVE_LLVM */
2203 2777
2204 // -------------------- jit_function_info -------------------- 2778 // -------------------- jit_function_info --------------------
2779 #ifdef HAVE_JIT
2205 jit_function_info::jit_function_info (tree_jit& tjit, 2780 jit_function_info::jit_function_info (tree_jit& tjit,
2206 octave_user_function& fcn, 2781 octave_user_function& fcn,
2207 const octave_value_list& ov_args) 2782 const octave_value_list& ov_args)
2208 : argument_types (ov_args.length ()), function (0) 2783 : argument_types (ov_args.length ()), function (0)
2209 { 2784 {
2215 jit_function wrapper; 2790 jit_function wrapper;
2216 2791
2217 try 2792 try
2218 { 2793 {
2219 jit_convert conv (fcn, argument_types); 2794 jit_convert conv (fcn, argument_types);
2795
2796 if (Vdebug_jit)
2797 {
2798 jit_block_list& blocks = conv.get_blocks ();
2799 blocks.label ();
2800 std::cout << "-------------------- Compiling function ";
2801 std::cout << "--------------------\n";
2802
2803 tree_print_code tpc (std::cout);
2804 tpc.visit_octave_user_function_header (fcn);
2805 tpc.visit_statement_list (*fcn.body ());
2806 tpc.visit_octave_user_function_trailer (fcn);
2807 blocks.print (std::cout, "octave jit ir");
2808 }
2809
2220 jit_infer infer (conv.get_factory (), conv.get_blocks (), 2810 jit_infer infer (conv.get_factory (), conv.get_blocks (),
2221 conv.get_variable_map ()); 2811 conv.get_variable_map ());
2222 infer.infer (); 2812 infer.infer ();
2223 2813
2224 if (Vdebug_jit) 2814 if (Vdebug_jit)
2251 } 2841 }
2252 2842
2253 std::string wrapper_name = fcn.name () + "_wrapper"; 2843 std::string wrapper_name = fcn.name () + "_wrapper";
2254 jit_type *any_t = jit_typeinfo::get_any (); 2844 jit_type *any_t = jit_typeinfo::get_any ();
2255 std::vector<jit_type *> wrapper_args (1, jit_typeinfo::get_any_ptr ()); 2845 std::vector<jit_type *> wrapper_args (1, jit_typeinfo::get_any_ptr ());
2256 wrapper = jit_function (module, jit_convention::internal, wrapper_name, 2846 wrapper = jit_function (module,
2847 #ifdef HAVE_GCCJIT
2848 gccjit::context (), // FIXME
2849 #endif
2850 jit_convention::internal, wrapper_name,
2257 any_t, wrapper_args); 2851 any_t, wrapper_args);
2258 2852
2259 llvm::BasicBlock *wrapper_body = wrapper.new_block (); 2853 llvm::BasicBlock *wrapper_body = wrapper.new_block ();
2260 builder.SetInsertPoint (wrapper_body); 2854 builder.SetInsertPoint (wrapper_body);
2261 2855
2316 2910
2317 wrapper.erase (); 2911 wrapper.erase ();
2318 raw_fn.erase (); 2912 raw_fn.erase ();
2319 } 2913 }
2320 } 2914 }
2915 #endif /* ifdef HAVE_JIT */
2321 2916
2322 bool 2917 bool
2323 jit_function_info::execute (const octave_value_list& ov_args, 2918 jit_function_info::execute (const octave_value_list& ov_args,
2324 octave_value_list& retval) const 2919 octave_value_list& retval) const
2325 { 2920 {
2361 2956
2362 return true; 2957 return true;
2363 } 2958 }
2364 2959
2365 // -------------------- jit_info -------------------- 2960 // -------------------- jit_info --------------------
2961 #ifdef HAVE_LLVM
2366 jit_info::jit_info (tree_jit& tjit, tree& tee) 2962 jit_info::jit_info (tree_jit& tjit, tree& tee)
2367 : engine (tjit.get_engine ()), function (0), llvm_function (0) 2963 : engine (tjit.get_engine ()), function (0), llvm_function (0)
2964 #ifdef HAVE_GCCJIT
2965 , gccjit_result (NULL)
2966 #endif
2368 { 2967 {
2369 compile (tjit, tee); 2968 compile (tjit, tee);
2370 } 2969 }
2371 2970
2372 jit_info::jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds) 2971 jit_info::jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds)
2373 : engine (tjit.get_engine ()), function (0), llvm_function (0) 2972 : engine (tjit.get_engine ()), function (0), llvm_function (0)
2973 #ifdef HAVE_GCCJIT
2974 , gccjit_result (NULL)
2975 #endif
2374 { 2976 {
2375 compile (tjit, tee, jit_typeinfo::type_of (for_bounds)); 2977 compile (tjit, tee, jit_typeinfo::type_of (for_bounds));
2376 } 2978 }
2377 2979
2378 jit_info::~jit_info (void) 2980 jit_info::~jit_info (void)
2379 { 2981 {
2380 if (llvm_function) 2982 if (llvm_function)
2381 llvm_function->eraseFromParent (); 2983 llvm_function->eraseFromParent ();
2382 } 2984 #ifdef HAVE_GCCJIT
2985 if (gccjit_result)
2986 gcc_jit_result_release (gccjit_result);
2987 #endif
2988 }
2989 #endif
2383 2990
2384 bool 2991 bool
2385 jit_info::execute (const vmap& extra_vars) const 2992 jit_info::execute (const vmap& extra_vars) const
2386 { 2993 {
2387 if (! function) 2994 if (! function)
2433 } 3040 }
2434 3041
2435 return true; 3042 return true;
2436 } 3043 }
2437 3044
3045 #ifdef HAVE_LLVM
2438 void 3046 void
2439 jit_info::compile (tree_jit& tjit, tree& tee, jit_type *for_bounds) 3047 jit_info::compile (tree_jit& tjit, tree& tee, jit_type *for_bounds)
2440 { 3048 {
2441 try 3049 try
2442 { 3050 {
2443 jit_convert conv (tee, for_bounds); 3051 jit_convert conv (tee, for_bounds);
3052
3053 if (Vdebug_jit)
3054 {
3055 jit_block_list& blocks = conv.get_blocks ();
3056 blocks.label ();
3057 std::cout << "-------------------- Compiling tree --------------------\n";
3058 std::cout << tee.str_print_code () << std::endl;
3059 blocks.print (std::cout, "octave jit ir");
3060 }
3061
2444 jit_infer infer (conv.get_factory (), conv.get_blocks (), 3062 jit_infer infer (conv.get_factory (), conv.get_blocks (),
2445 conv.get_variable_map ()); 3063 conv.get_variable_map ());
2446 3064
2447 infer.infer (); 3065 infer.infer ();
2448 3066
2454 std::cout << tee.str_print_code () << std::endl; 3072 std::cout << tee.str_print_code () << std::endl;
2455 blocks.print (std::cout, "octave jit ir"); 3073 blocks.print (std::cout, "octave jit ir");
2456 } 3074 }
2457 3075
2458 jit_factory& factory = conv.get_factory (); 3076 jit_factory& factory = conv.get_factory ();
3077
3078 #ifdef HAVE_GCCJIT
3079 jit_convert_gcc to_gcc;
3080 gccjit_result = to_gcc.convert_loop (infer.get_blocks (),
3081 factory.constants ());
3082 #endif
3083
2459 jit_convert_llvm to_llvm; 3084 jit_convert_llvm to_llvm;
2460 llvm_function = to_llvm.convert_loop (tjit.get_module (), 3085 llvm_function = to_llvm.convert_loop (tjit.get_module (),
2461 infer.get_blocks (), 3086 infer.get_blocks (),
2462 factory.constants ()); 3087 factory.constants ());
2463 arguments = to_llvm.get_arguments (); 3088 arguments = to_llvm.get_arguments ();
2472 } 3097 }
2473 3098
2474 Vjit_failcnt++; 3099 Vjit_failcnt++;
2475 3100
2476 } 3101 }
2477 3102 #ifdef HAVE_GCCJIT
3103 if (gccjit_result)
3104 {
3105 if (Vdebug_jit)
3106 {
3107 std::cout << "-------------------- gccjit --------------------";
3108 void *void_fn = gcc_jit_result_get_code (gccjit_result, "loop");
3109 function = reinterpret_cast<jited_function> (void_fn);
3110 }
3111 printf ("using gccjit function\n");
3112 }
3113 else
3114 #endif
2478 if (llvm_function) 3115 if (llvm_function)
2479 { 3116 {
2480 if (Vdebug_jit) 3117 if (Vdebug_jit)
2481 { 3118 {
2482 std::cout << "-------------------- llvm ir --------------------"; 3119 std::cout << "-------------------- llvm ir --------------------";
2495 3132
2496 void *void_fn = engine->getPointerToFunction (llvm_function); 3133 void *void_fn = engine->getPointerToFunction (llvm_function);
2497 function = reinterpret_cast<jited_function> (void_fn); 3134 function = reinterpret_cast<jited_function> (void_fn);
2498 } 3135 }
2499 } 3136 }
3137 #endif
2500 3138
2501 octave_value 3139 octave_value
2502 jit_info::find (const vmap& extra_vars, const std::string& vname) const 3140 jit_info::find (const vmap& extra_vars, const std::string& vname) const
2503 { 3141 {
2504 vmap::const_iterator iter = extra_vars.find (vname); 3142 vmap::const_iterator iter = extra_vars.find (vname);
2505 return iter == extra_vars.end () ? symbol_table::varval (vname) 3143 return iter == extra_vars.end () ? symbol_table::varval (vname)
2506 : *iter->second; 3144 : *iter->second;
2507 } 3145 }
2508 3146
3147 #endif /* if HAVE_JIT */
3148
3149 #if defined (HAVE_JIT)
3150 #define UNUSED_WITHOUT_JIT(x) x
3151 #else
3152 #define UNUSED_WITHOUT_JIT(x) x GCC_ATTR_UNUSED
2509 #endif 3153 #endif
2510 3154
2511 #if defined (HAVE_LLVM) 3155 DEFUN (jit_failcnt, UNUSED_WITHOUT_JIT (args),
2512 #define UNUSED_WITHOUT_LLVM(x) x 3156 UNUSED_WITHOUT_JIT (nargout),
2513 #else
2514 #define UNUSED_WITHOUT_LLVM(x) x GCC_ATTR_UNUSED
2515 #endif
2516
2517 DEFUN (jit_failcnt, UNUSED_WITHOUT_LLVM (args),
2518 UNUSED_WITHOUT_LLVM (nargout),
2519 "-*- texinfo -*-\n\ 3157 "-*- texinfo -*-\n\
2520 @deftypefn {Built-in Function} {@var{val} =} jit_failcnt ()\n\ 3158 @deftypefn {Built-in Function} {@var{val} =} jit_failcnt ()\n\
2521 @deftypefnx {Built-in Function} {@var{old_val} =} jit_failcnt (@var{new_val})\n\ 3159 @deftypefnx {Built-in Function} {@var{old_val} =} jit_failcnt (@var{new_val})\n\
2522 @deftypefnx {Built-in Function} {} jit_failcnt (@var{new_val}, \"local\")\n\ 3160 @deftypefnx {Built-in Function} {} jit_failcnt (@var{new_val}, \"local\")\n\
2523 Query or set the internal variable that counts the number of JIT fail\n\ 3161 Query or set the internal variable that counts the number of JIT fail\n\
2527 variable is changed locally for the function and any subroutines it calls.\n\ 3165 variable is changed locally for the function and any subroutines it calls.\n\
2528 The original variable value is restored when exiting the function.\n\ 3166 The original variable value is restored when exiting the function.\n\
2529 @seealso{jit_enable, jit_startcnt, debug_jit}\n\ 3167 @seealso{jit_enable, jit_startcnt, debug_jit}\n\
2530 @end deftypefn") 3168 @end deftypefn")
2531 { 3169 {
2532 #if defined (HAVE_LLVM) 3170 #if defined (HAVE_JIT)
2533 return SET_INTERNAL_VARIABLE (jit_failcnt); 3171 return SET_INTERNAL_VARIABLE (jit_failcnt);
2534 #else 3172 #else
2535 warning ("jit_failcnt: JIT compiling not available in this version of Octave"); 3173 warning ("jit_failcnt: JIT compiling not available in this version of Octave");
2536 return octave_value (); 3174 return octave_value ();
2537 #endif 3175 #endif
2538 } 3176 }
2539 3177
2540 DEFUN (debug_jit, UNUSED_WITHOUT_LLVM (args), 3178 DEFUN (debug_jit, UNUSED_WITHOUT_JIT (args),
2541 UNUSED_WITHOUT_LLVM (nargout), 3179 UNUSED_WITHOUT_JIT (nargout),
2542 "-*- texinfo -*-\n\ 3180 "-*- texinfo -*-\n\
2543 @deftypefn {Built-in Function} {@var{val} =} debug_jit ()\n\ 3181 @deftypefn {Built-in Function} {@var{val} =} debug_jit ()\n\
2544 @deftypefnx {Built-in Function} {@var{old_val} =} debug_jit (@var{new_val})\n\ 3182 @deftypefnx {Built-in Function} {@var{old_val} =} debug_jit (@var{new_val})\n\
2545 @deftypefnx {Built-in Function} {} debug_jit (@var{new_val}, \"local\")\n\ 3183 @deftypefnx {Built-in Function} {} debug_jit (@var{new_val}, \"local\")\n\
2546 Query or set the internal variable that determines whether\n\ 3184 Query or set the internal variable that determines whether\n\
2550 variable is changed locally for the function and any subroutines it calls.\n\ 3188 variable is changed locally for the function and any subroutines it calls.\n\
2551 The original variable value is restored when exiting the function.\n\ 3189 The original variable value is restored when exiting the function.\n\
2552 @seealso{jit_enable, jit_startcnt}\n\ 3190 @seealso{jit_enable, jit_startcnt}\n\
2553 @end deftypefn") 3191 @end deftypefn")
2554 { 3192 {
2555 #if defined (HAVE_LLVM) 3193 #if defined (HAVE_JIT)
2556 return SET_INTERNAL_VARIABLE (debug_jit); 3194 return SET_INTERNAL_VARIABLE (debug_jit);
2557 #else 3195 #else
2558 warning ("debug_jit: JIT compiling not available in this version of Octave"); 3196 warning ("debug_jit: JIT compiling not available in this version of Octave");
2559 return octave_value (); 3197 return octave_value ();
2560 #endif 3198 #endif
2561 } 3199 }
2562 3200
2563 DEFUN (jit_enable, UNUSED_WITHOUT_LLVM (args), 3201 DEFUN (jit_enable, UNUSED_WITHOUT_JIT (args),
2564 UNUSED_WITHOUT_LLVM (nargout), 3202 UNUSED_WITHOUT_JIT (nargout),
2565 "-*- texinfo -*-\n\ 3203 "-*- texinfo -*-\n\
2566 @deftypefn {Built-in Function} {@var{val} =} jit_enable ()\n\ 3204 @deftypefn {Built-in Function} {@var{val} =} jit_enable ()\n\
2567 @deftypefnx {Built-in Function} {@var{old_val} =} jit_enable (@var{new_val})\n\ 3205 @deftypefnx {Built-in Function} {@var{old_val} =} jit_enable (@var{new_val})\n\
2568 @deftypefnx {Built-in Function} {} jit_enable (@var{new_val}, \"local\")\n\ 3206 @deftypefnx {Built-in Function} {} jit_enable (@var{new_val}, \"local\")\n\
2569 Query or set the internal variable that enables Octave's JIT compiler.\n\ 3207 Query or set the internal variable that enables Octave's JIT compiler.\n\
2572 variable is changed locally for the function and any subroutines it calls.\n\ 3210 variable is changed locally for the function and any subroutines it calls.\n\
2573 The original variable value is restored when exiting the function.\n\ 3211 The original variable value is restored when exiting the function.\n\
2574 @seealso{jit_startcnt, debug_jit}\n\ 3212 @seealso{jit_startcnt, debug_jit}\n\
2575 @end deftypefn") 3213 @end deftypefn")
2576 { 3214 {
2577 #if defined (HAVE_LLVM) 3215 #if defined (HAVE_JIT)
2578 return SET_INTERNAL_VARIABLE (jit_enable); 3216 return SET_INTERNAL_VARIABLE (jit_enable);
2579 #else 3217 #else
2580 warning ("jit_enable: JIT compiling not available in this version of Octave"); 3218 warning ("jit_enable: JIT compiling not available in this version of Octave");
2581 return octave_value (); 3219 return octave_value ();
2582 #endif 3220 #endif
2583 } 3221 }
2584 3222
2585 DEFUN (jit_startcnt, UNUSED_WITHOUT_LLVM (args), 3223 DEFUN (jit_startcnt, UNUSED_WITHOUT_JIT (args),
2586 UNUSED_WITHOUT_LLVM (nargout), 3224 UNUSED_WITHOUT_JIT (nargout),
2587 "-*- texinfo -*-\n\ 3225 "-*- texinfo -*-\n\
2588 @deftypefn {Built-in Function} {@var{val} =} jit_startcnt ()\n\ 3226 @deftypefn {Built-in Function} {@var{val} =} jit_startcnt ()\n\
2589 @deftypefnx {Built-in Function} {@var{old_val} =} jit_startcnt (@var{new_val})\n\ 3227 @deftypefnx {Built-in Function} {@var{old_val} =} jit_startcnt (@var{new_val})\n\
2590 @deftypefnx {Built-in Function} {} jit_startcnt (@var{new_val}, \"local\")\n\ 3228 @deftypefnx {Built-in Function} {} jit_startcnt (@var{new_val}, \"local\")\n\
2591 Query or set the internal variable that determines whether JIT compilation\n\ 3229 Query or set the internal variable that determines whether JIT compilation\n\
2599 variable is changed locally for the function and any subroutines it calls.\n\ 3237 variable is changed locally for the function and any subroutines it calls.\n\
2600 The original variable value is restored when exiting the function.\n\ 3238 The original variable value is restored when exiting the function.\n\
2601 @seealso{jit_enable, jit_failcnt, debug_jit}\n\ 3239 @seealso{jit_enable, jit_failcnt, debug_jit}\n\
2602 @end deftypefn") 3240 @end deftypefn")
2603 { 3241 {
2604 #if defined (HAVE_LLVM) 3242 #if defined (HAVE_JIT)
2605 return SET_INTERNAL_VARIABLE_WITH_LIMITS (jit_startcnt, 1, 3243 return SET_INTERNAL_VARIABLE_WITH_LIMITS (jit_startcnt, 1,
2606 std::numeric_limits<int>::max ()); 3244 std::numeric_limits<int>::max ());
2607 #else 3245 #else
2608 warning ("jit_enable: JIT compiling not available in this version of Octave"); 3246 warning ("jit_enable: JIT compiling not available in this version of Octave");
2609 return octave_value (); 3247 return octave_value ();