Skip to content
This repository
Browse code

floating point arithmetic optimization: Float objects are now immedia…

…te types and we generate optimized machine code for arithmetic operations dealing with floats

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/experimental@1870 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
commit 01528a725728304b8d725f4247d71e5e25a298e3 1 parent 15a24d2
Laurent Sansonetti authored
524 compiler.cpp
@@ -123,6 +123,7 @@ RoxorCompiler::RoxorCompiler(const char *_fname)
123 123 zeroVal = ConstantInt::get(IntTy, 0);
124 124 oneVal = ConstantInt::get(IntTy, 1);
125 125 twoVal = ConstantInt::get(IntTy, 2);
  126 + threeVal = ConstantInt::get(IntTy, 3);
126 127
127 128 RubyObjPtrTy = PointerType::getUnqual(RubyObjTy);
128 129 RubyObjPtrPtrTy = PointerType::getUnqual(RubyObjPtrTy);
@@ -1514,8 +1515,182 @@ RoxorCompiler::compile_rethrow_exception(void)
1514 1515 new UnreachableInst(bb);
1515 1516 }
1516 1517
  1518 +typedef struct rb_vm_immediate_val {
  1519 + int type;
  1520 + union {
  1521 + long l;
  1522 + double d;
  1523 + } v;
  1524 + rb_vm_immediate_val(void) { type = 0; }
  1525 + bool is_fixnum(void) { return type == T_FIXNUM; }
  1526 + bool is_float(void) { return type == T_FLOAT; }
  1527 + long long_val(void) { return is_fixnum() ? v.l : (long)v.d; }
  1528 + double double_val(void) { return is_float() ? v.d : (double)v.l; }
  1529 +} rb_vm_immediate_val_t;
  1530 +
  1531 +static bool
  1532 +unbox_immediate_val(VALUE rval, rb_vm_immediate_val_t *val)
  1533 +{
  1534 + if (rval != Qundef) {
  1535 + if (FIXNUM_P(rval)) {
  1536 + val->type = T_FIXNUM;
  1537 + val->v.l = FIX2LONG(rval);
  1538 + return true;
  1539 + }
  1540 + else if (FIXFLOAT_P(rval)) {
  1541 + val->type = T_FLOAT;
  1542 + val->v.d = FIXFLOAT2DBL(rval);
  1543 + return true;
  1544 + }
  1545 + }
  1546 + return false;
  1547 +}
  1548 +
  1549 +template <class T> static bool
  1550 +optimized_const_immediate_op(SEL sel, T leftVal, T rightVal,
  1551 + bool *is_predicate, T *res_p)
  1552 +{
  1553 + T res;
  1554 + if (sel == selPLUS) {
  1555 + res = leftVal + rightVal;
  1556 + }
  1557 + else if (sel == selMINUS) {
  1558 + res = leftVal - rightVal;
  1559 + }
  1560 + else if (sel == selDIV) {
  1561 + if (rightVal == 0) {
  1562 + return false;
  1563 + }
  1564 + res = leftVal / rightVal;
  1565 + }
  1566 + else if (sel == selMULT) {
  1567 + res = leftVal * rightVal;
  1568 + }
  1569 + else {
  1570 + *is_predicate = true;
  1571 + if (sel == selLT) {
  1572 + res = leftVal < rightVal;
  1573 + }
  1574 + else if (sel == selLE) {
  1575 + res = leftVal <= rightVal;
  1576 + }
  1577 + else if (sel == selGT) {
  1578 + res = leftVal > rightVal;
  1579 + }
  1580 + else if (sel == selGE) {
  1581 + res = leftVal >= rightVal;
  1582 + }
  1583 + else if (sel == selEq || sel == selEqq) {
  1584 + res = leftVal == rightVal;
  1585 + }
  1586 + else if (sel == selNeq) {
  1587 + res = leftVal != rightVal;
  1588 + }
  1589 + else {
  1590 + abort();
  1591 + }
  1592 + }
  1593 + *res_p = res;
  1594 + return true;
  1595 +}
  1596 +
1517 1597 Value *
1518   -RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> &params)
  1598 +RoxorCompiler::optimized_immediate_op(SEL sel, Value *leftVal, Value *rightVal,
  1599 + bool float_op, bool *is_predicate)
  1600 +{
  1601 + Value *res;
  1602 + if (sel == selPLUS) {
  1603 + res = BinaryOperator::CreateAdd(leftVal, rightVal, "", bb);
  1604 + }
  1605 + else if (sel == selMINUS) {
  1606 + res = BinaryOperator::CreateSub(leftVal, rightVal, "", bb);
  1607 + }
  1608 + else if (sel == selDIV) {
  1609 + res = float_op
  1610 + ? BinaryOperator::CreateFDiv(leftVal, rightVal, "", bb)
  1611 + : BinaryOperator::CreateSDiv(leftVal, rightVal, "", bb);
  1612 +
  1613 + }
  1614 + else if (sel == selMULT) {
  1615 + res = BinaryOperator::CreateMul(leftVal, rightVal, "", bb);
  1616 + }
  1617 + else {
  1618 + *is_predicate = true;
  1619 +
  1620 + CmpInst::Predicate predicate;
  1621 +
  1622 + if (sel == selLT) {
  1623 + predicate = float_op ? FCmpInst::FCMP_OLT : ICmpInst::ICMP_SLT;
  1624 + }
  1625 + else if (sel == selLE) {
  1626 + predicate = float_op ? FCmpInst::FCMP_OLE : ICmpInst::ICMP_SLE;
  1627 + }
  1628 + else if (sel == selGT) {
  1629 + predicate = float_op ? FCmpInst::FCMP_OGT : ICmpInst::ICMP_SGT;
  1630 + }
  1631 + else if (sel == selGE) {
  1632 + predicate = float_op ? FCmpInst::FCMP_OGE : ICmpInst::ICMP_SGE;
  1633 + }
  1634 + else if (sel == selEq || sel == selEqq) {
  1635 + predicate = float_op ? FCmpInst::FCMP_OEQ : ICmpInst::ICMP_EQ;
  1636 + }
  1637 + else if (sel == selNeq) {
  1638 + predicate = float_op ? FCmpInst::FCMP_ONE : ICmpInst::ICMP_NE;
  1639 + }
  1640 + else {
  1641 + abort();
  1642 + }
  1643 +
  1644 + if (float_op) {
  1645 + res = new FCmpInst(predicate, leftVal, rightVal, "", bb);
  1646 + }
  1647 + else {
  1648 + res = new ICmpInst(predicate, leftVal, rightVal, "", bb);
  1649 + }
  1650 + res = SelectInst::Create(res, trueVal, falseVal, "", bb);
  1651 + }
  1652 + return res;
  1653 +}
  1654 +
  1655 +Value *
  1656 +RoxorCompiler::compile_double_coercion(Value *val, Value *mask,
  1657 + BasicBlock *fallback_bb, Function *f)
  1658 +{
  1659 + Value *is_float = new ICmpInst(ICmpInst::ICMP_EQ,
  1660 + mask, threeVal, "", bb);
  1661 +
  1662 + BasicBlock *is_float_bb = BasicBlock::Create("is_float", f);
  1663 + BasicBlock *isnt_float_bb = BasicBlock::Create("isnt_float", f);
  1664 + BasicBlock *merge_bb = BasicBlock::Create("merge", f);
  1665 +
  1666 + BranchInst::Create(is_float_bb, isnt_float_bb, is_float, bb);
  1667 +
  1668 + bb = is_float_bb;
  1669 + Value *is_float_val = BinaryOperator::CreateXor(val, threeVal, "", bb);
  1670 + is_float_val = new BitCastInst(is_float_val, Type::DoubleTy, "", bb);
  1671 + BranchInst::Create(merge_bb, bb);
  1672 +
  1673 + bb = isnt_float_bb;
  1674 + Value *is_fixnum = new ICmpInst(ICmpInst::ICMP_EQ, mask, oneVal, "", bb);
  1675 + BasicBlock *is_fixnum_bb = BasicBlock::Create("is_fixnum", f);
  1676 + BranchInst::Create(is_fixnum_bb, fallback_bb, is_fixnum, bb);
  1677 +
  1678 + bb = is_fixnum_bb;
  1679 + Value *is_fixnum_val = BinaryOperator::CreateAShr(val, twoVal, "", bb);
  1680 + is_fixnum_val = new SIToFPInst(is_fixnum_val, Type::DoubleTy, "", bb);
  1681 + BranchInst::Create(merge_bb, bb);
  1682 +
  1683 + bb = merge_bb;
  1684 + PHINode *pn = PHINode::Create(Type::DoubleTy, "op_tmp", bb);
  1685 + pn->addIncoming(is_float_val, is_float_bb);
  1686 + pn->addIncoming(is_fixnum_val, is_fixnum_bb);
  1687 +
  1688 + return pn;
  1689 +}
  1690 +
  1691 +Value *
  1692 +RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc,
  1693 + std::vector<Value *> &params)
1519 1694 {
1520 1695 // The not operator (!).
1521 1696 if (sel == selNot) {
@@ -1560,7 +1735,7 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
1560 1735 Value *leftVal = params[1]; // self
1561 1736 Value *rightVal = params.back();
1562 1737
1563   - VALUE leftRVal = 0, rightRVal = 0;
  1738 + VALUE leftRVal = Qundef, rightRVal = Qundef;
1564 1739 const bool leftIsConstant = unbox_ruby_constant(leftVal, &leftRVal);
1565 1740 const bool rightIsConst = unbox_ruby_constant(rightVal, &rightRVal);
1566 1741
@@ -1608,57 +1783,52 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
1608 1783 }
1609 1784 }
1610 1785
1611   - const bool leftIsFixnumConstant = FIXNUM_P(leftRVal);
1612   - const bool rightIsFixnumConstant = FIXNUM_P(rightRVal);
1613   -
1614   - long leftLong = leftIsFixnumConstant ? FIX2LONG(leftRVal) : 0;
1615   - long rightLong = rightIsFixnumConstant ? FIX2LONG(rightRVal) : 0;
1616   -
1617   - if (leftIsFixnumConstant && rightIsFixnumConstant) {
1618   - // Both operands are fixnum constants.
1619   - bool result_is_fixnum = true;
1620   - long res;
1621   -
1622   - if (sel == selPLUS) {
1623   - res = leftLong + rightLong;
1624   - }
1625   - else if (sel == selMINUS) {
1626   - res = leftLong - rightLong;
1627   - }
1628   - else if (sel == selDIV) {
1629   - if (rightLong == 0) {
1630   - return NULL;
  1786 + rb_vm_immediate_val_t leftImm, rightImm;
  1787 + const bool leftIsImmediateConst = unbox_immediate_val(leftRVal,
  1788 + &leftImm);
  1789 + const bool rightIsImmediateConst = unbox_immediate_val(rightRVal,
  1790 + &rightImm);
  1791 +
  1792 + if (leftIsImmediateConst && rightIsImmediateConst) {
  1793 + Value *res_val = NULL;
  1794 +
  1795 + if (leftImm.is_fixnum() && rightImm.is_fixnum()) {
  1796 + bool result_is_predicate = false;
  1797 + long res;
  1798 + if (optimized_const_immediate_op<long>(
  1799 + sel,
  1800 + leftImm.long_val(),
  1801 + rightImm.long_val(),
  1802 + &result_is_predicate,
  1803 + &res)) {
  1804 + if (result_is_predicate) {
  1805 + res_val = res == 1 ? trueVal : falseVal;
  1806 + }
  1807 + else if (FIXABLE(res)) {
  1808 + res_val = ConstantInt::get(RubyObjTy, LONG2FIX(res));
  1809 + }
1631 1810 }
1632   - res = leftLong / rightLong;
1633   - }
1634   - else if (sel == selMULT) {
1635   - res = leftLong * rightLong;
1636 1811 }
1637 1812 else {
1638   - result_is_fixnum = false;
1639   - if (sel == selLT) {
1640   - res = leftLong < rightLong;
1641   - }
1642   - else if (sel == selLE) {
1643   - res = leftLong <= rightLong;
1644   - }
1645   - else if (sel == selGT) {
1646   - res = leftLong > rightLong;
1647   - }
1648   - else if (sel == selGE) {
1649   - res = leftLong >= rightLong;
1650   - }
1651   - else if ((sel == selEq) || (sel == selEqq)) {
1652   - res = leftLong == rightLong;
1653   - }
1654   - else if (sel == selNeq) {
1655   - res = leftLong != rightLong;
1656   - }
1657   - else {
1658   - abort();
  1813 + bool result_is_predicate = false;
  1814 + double res;
  1815 + if (optimized_const_immediate_op<double>(
  1816 + sel,
  1817 + leftImm.double_val(),
  1818 + rightImm.double_val(),
  1819 + &result_is_predicate,
  1820 + &res)) {
  1821 + if (result_is_predicate) {
  1822 + res_val = res == 1 ? trueVal : falseVal;
  1823 + }
  1824 + else {
  1825 + res_val = ConstantInt::get(RubyObjTy,
  1826 + DBL2FIXFLOAT(res));
  1827 + }
1659 1828 }
1660 1829 }
1661   - if (!result_is_fixnum || FIXABLE(res)) {
  1830 +
  1831 + if (res_val != NULL) {
1662 1832 Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
1663 1833 Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
1664 1834 is_redefined_val, ConstantInt::getFalse(), "", bb);
@@ -1670,9 +1840,7 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
1670 1840 BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
1671 1841
1672 1842 BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
1673   - Value *thenVal = result_is_fixnum
1674   - ? ConstantInt::get(RubyObjTy, LONG2FIX(res))
1675   - : (res == 1 ? trueVal : falseVal);
  1843 + Value *thenVal = res_val;
1676 1844 BranchInst::Create(mergeBB, thenBB);
1677 1845
1678 1846 bb = elseBB;
@@ -1687,169 +1855,188 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
1687 1855
1688 1856 return pn;
1689 1857 }
1690   - // Non fixable (bignum), call the dispatcher.
  1858 + // Can't optimize, call the dispatcher.
1691 1859 return NULL;
1692 1860 }
1693 1861 else {
1694   - // Either one or both is not a constant fixnum.
  1862 + // Either one or both is not a constant immediate.
1695 1863 Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
1696 1864 Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
1697 1865 is_redefined_val, ConstantInt::getFalse(), "", bb);
1698 1866
1699 1867 Function *f = bb->getParent();
1700 1868
1701   - BasicBlock *then1BB = BasicBlock::Create("op_not_redefined", f);
1702   - BasicBlock *then2BB = BasicBlock::Create("op_optimize", f);
1703   - BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
1704   - BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
  1869 + BasicBlock *not_redefined_bb =
  1870 + BasicBlock::Create("op_not_redefined", f);
  1871 + BasicBlock *optimize_fixnum_bb =
  1872 + BasicBlock::Create("op_optimize_fixnum", f);
  1873 + BasicBlock *optimize_float_bb =
  1874 + BasicBlock::Create("op_optimize_float", f);
  1875 + BasicBlock *dispatch_bb = BasicBlock::Create("op_dispatch", f);
  1876 + BasicBlock *merge_bb = BasicBlock::Create("op_merge", f);
1705 1877
1706   - BranchInst::Create(then1BB, elseBB, isOpRedefined, bb);
  1878 + BranchInst::Create(not_redefined_bb, dispatch_bb, isOpRedefined,
  1879 + bb);
1707 1880
1708   - bb = then1BB;
  1881 + bb = not_redefined_bb;
1709 1882
1710 1883 Value *leftAndOp = NULL;
1711   - if (!leftIsFixnumConstant) {
1712   - leftAndOp = BinaryOperator::CreateAnd(leftVal, oneVal, "",
  1884 + if (!leftIsImmediateConst) {
  1885 + leftAndOp = BinaryOperator::CreateAnd(leftVal, threeVal, "",
1713 1886 bb);
1714 1887 }
1715 1888
1716 1889 Value *rightAndOp = NULL;
1717   - if (!rightIsFixnumConstant) {
1718   - rightAndOp = BinaryOperator::CreateAnd(rightVal, oneVal, "",
  1890 + if (!rightIsImmediateConst) {
  1891 + rightAndOp = BinaryOperator::CreateAnd(rightVal, threeVal, "",
1719 1892 bb);
1720 1893 }
1721 1894
1722   - Value *areFixnums = NULL;
1723 1895 if (leftAndOp != NULL && rightAndOp != NULL) {
1724   - Value *foo = BinaryOperator::CreateAdd(leftAndOp, rightAndOp,
1725   - "", bb);
1726   - areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, foo, twoVal, "", bb);
  1896 + Value *leftIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
  1897 + leftAndOp, oneVal, "", bb);
  1898 + BasicBlock *left_is_fixnum_bb =
  1899 + BasicBlock::Create("left_fixnum", f);
  1900 + BranchInst::Create(left_is_fixnum_bb, optimize_float_bb,
  1901 + leftIsFixnum, bb);
  1902 +
  1903 + bb = left_is_fixnum_bb;
  1904 + Value *rightIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
  1905 + rightAndOp, oneVal, "", bb);
  1906 + BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
  1907 + rightIsFixnum, bb);
1727 1908 }
1728 1909 else if (leftAndOp != NULL) {
1729   - areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, leftAndOp, oneVal, "", bb);
1730   - }
1731   - else {
1732   - areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, rightAndOp, oneVal, "", bb);
1733   - }
1734   -
1735   - Value *fastEqqVal = NULL;
1736   - BasicBlock *fastEqqBB = NULL;
1737   - if (sel == selEqq) {
1738   - // compile_fast_eqq_call won't be called if #=== has been redefined
1739   - // fixnum optimizations are done separately
1740   - fastEqqBB = BasicBlock::Create("fast_eqq", f);
1741   - BranchInst::Create(then2BB, fastEqqBB, areFixnums, bb);
1742   - bb = fastEqqBB;
1743   - fastEqqVal = compile_fast_eqq_call(leftVal, rightVal);
1744   - fastEqqBB = bb;
1745   - BranchInst::Create(mergeBB, bb);
  1910 + if (rightImm.is_fixnum()) {
  1911 + Value *leftIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
  1912 + leftAndOp, oneVal, "", bb);
  1913 + BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
  1914 + leftIsFixnum, bb);
  1915 + }
  1916 + else {
  1917 + BranchInst::Create(optimize_float_bb, bb);
  1918 + }
1746 1919 }
1747   - else {
1748   - BranchInst::Create(then2BB, elseBB, areFixnums, bb);
  1920 + else if (rightAndOp != NULL) {
  1921 + if (leftImm.is_fixnum()) {
  1922 + Value *rightIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
  1923 + rightAndOp, oneVal, "", bb);
  1924 + BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
  1925 + rightIsFixnum, bb);
  1926 + }
  1927 + else {
  1928 + BranchInst::Create(optimize_float_bb, bb);
  1929 + }
1749 1930 }
1750   - bb = then2BB;
  1931 +
  1932 + bb = optimize_fixnum_bb;
1751 1933
1752 1934 Value *unboxedLeft;
1753   - if (leftIsFixnumConstant) {
1754   - unboxedLeft = ConstantInt::get(RubyObjTy, leftLong);
  1935 + if (leftIsImmediateConst) {
  1936 + unboxedLeft = ConstantInt::get(IntTy, leftImm.long_val());
1755 1937 }
1756 1938 else {
1757   - unboxedLeft = BinaryOperator::CreateAShr(leftVal, oneVal, "", bb);
  1939 + unboxedLeft = BinaryOperator::CreateAShr(leftVal, twoVal, "",
  1940 + bb);
1758 1941 }
1759 1942
1760 1943 Value *unboxedRight;
1761   - if (rightIsFixnumConstant) {
1762   - unboxedRight = ConstantInt::get(RubyObjTy, rightLong);
1763   - }
1764   - else {
1765   - unboxedRight = BinaryOperator::CreateAShr(rightVal, oneVal, "", bb);
1766   - }
1767   -
1768   - Value *opVal;
1769   - bool result_is_fixnum = true;
1770   - if (sel == selPLUS) {
1771   - opVal = BinaryOperator::CreateAdd(unboxedLeft, unboxedRight, "", bb);
1772   - }
1773   - else if (sel == selMINUS) {
1774   - opVal = BinaryOperator::CreateSub(unboxedLeft, unboxedRight, "", bb);
1775   - }
1776   - else if (sel == selDIV) {
1777   - opVal = BinaryOperator::CreateSDiv(unboxedLeft, unboxedRight, "", bb);
1778   - }
1779   - else if (sel == selMULT) {
1780   - opVal = BinaryOperator::CreateMul(unboxedLeft, unboxedRight, "", bb);
  1944 + if (rightIsImmediateConst) {
  1945 + unboxedRight = ConstantInt::get(IntTy, rightImm.long_val());
1781 1946 }
1782 1947 else {
1783   - result_is_fixnum = false;
1784   -
1785   - CmpInst::Predicate predicate;
1786   -
1787   - if (sel == selLT) {
1788   - predicate = ICmpInst::ICMP_SLT;
1789   - }
1790   - else if (sel == selLE) {
1791   - predicate = ICmpInst::ICMP_SLE;
1792   - }
1793   - else if (sel == selGT) {
1794   - predicate = ICmpInst::ICMP_SGT;
1795   - }
1796   - else if (sel == selGE) {
1797   - predicate = ICmpInst::ICMP_SGE;
1798   - }
1799   - else if ((sel == selEq) || (sel == selEqq)) {
1800   - predicate = ICmpInst::ICMP_EQ;
1801   - }
1802   - else if (sel == selNeq) {
1803   - predicate = ICmpInst::ICMP_NE;
1804   - }
1805   - else {
1806   - abort();
1807   - }
1808   -
1809   - opVal = new ICmpInst(predicate, unboxedLeft, unboxedRight, "", bb);
1810   - opVal = SelectInst::Create(opVal, trueVal, falseVal, "", bb);
  1948 + unboxedRight = BinaryOperator::CreateAShr(rightVal, twoVal, "",
  1949 + bb);
1811 1950 }
1812 1951
1813   - Value *thenVal;
1814   - BasicBlock *then3BB;
  1952 + bool result_is_predicate = false;
  1953 + Value *fix_op_res = optimized_immediate_op(sel, unboxedLeft,
  1954 + unboxedRight, false, &result_is_predicate);
1815 1955
1816   - if (result_is_fixnum) {
1817   - Value *shift = BinaryOperator::CreateShl(opVal, oneVal, "", bb);
1818   - thenVal = BinaryOperator::CreateOr(shift, oneVal, "", bb);
  1956 + if (!result_is_predicate) {
  1957 + // Box the fixnum.
  1958 + Value *shift = BinaryOperator::CreateShl(fix_op_res, twoVal, "",
  1959 + bb);
  1960 + Value *boxed_op_res = BinaryOperator::CreateOr(shift, oneVal,
  1961 + "", bb);
1819 1962
1820 1963 // Is result fixable?
1821 1964 Value *fixnumMax = ConstantInt::get(IntTy, FIXNUM_MAX + 1);
1822   - Value *isFixnumMaxOk = new ICmpInst(ICmpInst::ICMP_SLT, opVal, fixnumMax, "", bb);
  1965 + Value *isFixnumMaxOk = new ICmpInst(ICmpInst::ICMP_SLT,
  1966 + fix_op_res, fixnumMax, "", bb);
1823 1967
1824   - then3BB = BasicBlock::Create("op_fixable_max", f);
  1968 + BasicBlock *fixable_max_bb =
  1969 + BasicBlock::Create("op_fixable_max", f);
1825 1970
1826   - BranchInst::Create(then3BB, elseBB, isFixnumMaxOk, bb);
  1971 + BranchInst::Create(fixable_max_bb, dispatch_bb, isFixnumMaxOk,
  1972 + bb);
1827 1973
1828   - bb = then3BB;
  1974 + bb = fixable_max_bb;
1829 1975 Value *fixnumMin = ConstantInt::get(IntTy, FIXNUM_MIN);
1830   - Value *isFixnumMinOk = new ICmpInst(ICmpInst::ICMP_SGE, opVal, fixnumMin, "", bb);
  1976 + Value *isFixnumMinOk = new ICmpInst(ICmpInst::ICMP_SGE,
  1977 + fix_op_res, fixnumMin, "", bb);
  1978 +
  1979 + BranchInst::Create(merge_bb, dispatch_bb, isFixnumMinOk, bb);
  1980 + fix_op_res = boxed_op_res;
  1981 + optimize_fixnum_bb = fixable_max_bb;
  1982 + }
  1983 + else {
  1984 + BranchInst::Create(merge_bb, bb);
  1985 + }
  1986 +
  1987 + bb = optimize_float_bb;
  1988 +
  1989 + if (leftIsImmediateConst) {
  1990 + unboxedLeft = ConstantFP::get(Type::DoubleTy,
  1991 + leftImm.double_val());
  1992 + }
  1993 + else {
  1994 + unboxedLeft = compile_double_coercion(leftVal, leftAndOp,
  1995 + dispatch_bb, f);
  1996 + }
1831 1997
1832   - BranchInst::Create(mergeBB, elseBB, isFixnumMinOk, bb);
  1998 + if (rightIsImmediateConst) {
  1999 + unboxedRight = ConstantFP::get(Type::DoubleTy,
  2000 + rightImm.double_val());
1833 2001 }
1834 2002 else {
1835   - thenVal = opVal;
1836   - then3BB = then2BB;
1837   - BranchInst::Create(mergeBB, then3BB);
  2003 + unboxedRight = compile_double_coercion(rightVal, rightAndOp,
  2004 + dispatch_bb, f);
1838 2005 }
1839 2006
1840   - bb = elseBB;
1841   - Value *elseVal = compile_dispatch_call(params);
1842   - elseBB = bb;
1843   - BranchInst::Create(mergeBB, elseBB);
  2007 + result_is_predicate = false;
  2008 + Value *flp_op_res = optimized_immediate_op(sel, unboxedLeft,
  2009 + unboxedRight, true, &result_is_predicate);
1844 2010
1845   - bb = mergeBB;
1846   - PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
1847   - pn->addIncoming(thenVal, then3BB);
1848   - pn->addIncoming(elseVal, elseBB);
  2011 + if (!result_is_predicate) {
  2012 + // Box the float.
  2013 + flp_op_res = new BitCastInst(flp_op_res, RubyObjTy, "", bb);
  2014 + flp_op_res = BinaryOperator::CreateOr(flp_op_res, threeVal,
  2015 + "", bb);
  2016 + }
  2017 + optimize_float_bb = bb;
  2018 + BranchInst::Create(merge_bb, bb);
1849 2019
  2020 + bb = dispatch_bb;
  2021 + Value *dispatch_val;
1850 2022 if (sel == selEqq) {
1851   - pn->addIncoming(fastEqqVal, fastEqqBB);
  2023 + dispatch_val = compile_fast_eqq_call(leftVal, rightVal);
1852 2024 }
  2025 + else {
  2026 + dispatch_val = compile_dispatch_call(params);
  2027 + }
  2028 + dispatch_bb = bb;
  2029 + BranchInst::Create(merge_bb, bb);
  2030 +
  2031 + bb = merge_bb;
  2032 + PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", bb);
  2033 + pn->addIncoming(fix_op_res, optimize_fixnum_bb);
  2034 + pn->addIncoming(flp_op_res, optimize_float_bb);
  2035 + pn->addIncoming(dispatch_val, dispatch_bb);
  2036 +
  2037 +// if (sel == selEqq) {
  2038 +// pn->addIncoming(fastEqqVal, fastEqqBB);
  2039 +// }
1853 2040
1854 2041 return pn;
1855 2042 }
@@ -4896,7 +5083,7 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
4896 5083 case _C_SHT:
4897 5084 case _C_INT:
4898 5085 val = new SExtInst(val, RubyObjTy, "", bb);
4899   - val = BinaryOperator::CreateShl(val, oneVal, "", bb);
  5086 + val = BinaryOperator::CreateShl(val, twoVal, "", bb);
4900 5087 val = BinaryOperator::CreateOr(val, oneVal, "", bb);
4901 5088 return val;
4902 5089
@@ -4904,7 +5091,7 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
4904 5091 case _C_USHT:
4905 5092 case _C_UINT:
4906 5093 val = new ZExtInst(val, RubyObjTy, "", bb);
4907   - val = BinaryOperator::CreateShl(val, oneVal, "", bb);
  5094 + val = BinaryOperator::CreateShl(val, twoVal, "", bb);
4908 5095 val = BinaryOperator::CreateOr(val, oneVal, "", bb);
4909 5096 return val;
4910 5097
@@ -4925,15 +5112,12 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
4925 5112 break;
4926 5113
4927 5114 case _C_FLT:
4928   - {
4929   - char buf = _C_DBL;
4930   - const Type *dbl_type = convert_type(&buf);
4931   - val = new FPExtInst(val, dbl_type, "", bb);
4932   - llvm_type = dbl_type;
4933   - }
  5115 + val = new FPExtInst(val, Type::DoubleTy, "", bb);
4934 5116 // fall through
4935 5117 case _C_DBL:
4936   - func_name = "rb_float_new";
  5118 + val = new BitCastInst(val, RubyObjTy, "", bb);
  5119 + val = BinaryOperator::CreateOr(val, threeVal, "", bb);
  5120 + return val;
4937 5121 break;
4938 5122
4939 5123 case _C_SEL:
6 compiler.h
@@ -148,6 +148,7 @@ class RoxorCompiler {
148 148 Constant *zeroVal;
149 149 Constant *oneVal;
150 150 Constant *twoVal;
  151 + Constant *threeVal;
151 152 Constant *nilVal;
152 153 Constant *trueVal;
153 154 Constant *falseVal;
@@ -267,6 +268,11 @@ class RoxorCompiler {
267 268 void compile_ivar_slots(Value *klass, BasicBlock::InstListType &list,
268 269 BasicBlock::InstListType::iterator iter);
269 270 bool unbox_ruby_constant(Value *val, VALUE *rval);
  271 + Value *optimized_immediate_op(SEL sel, Value *leftVal, Value *rightVal,
  272 + bool float_op, bool *is_predicate);
  273 + Value *compile_double_coercion(Value *val, Value *mask,
  274 + BasicBlock *fallback_bb, Function *f);
  275 +
270 276 SEL mid_to_sel(ID mid, int arity);
271 277 };
272 278
47 include/ruby/ruby.h
@@ -167,10 +167,10 @@ typedef unsigned LONG_LONG ID;
167 167 # endif
168 168 #endif
169 169
170   -#define FIXNUM_MAX (LONG_MAX>>1)
171   -#define FIXNUM_MIN RSHIFT((long)LONG_MIN,1)
  170 +#define FIXNUM_MAX (LONG_MAX>>2)
  171 +#define FIXNUM_MIN RSHIFT((long)LONG_MIN,2)
172 172
173   -#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))
  173 +#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<2 | FIXNUM_FLAG))
174 174 #define LONG2FIX(i) INT2FIX(i)
175 175 #define rb_fix_new(v) INT2FIX(v)
176 176 VALUE rb_int2inum(SIGNED_VALUE);
@@ -224,15 +224,21 @@ VALUE rb_ull2inum(unsigned LONG_LONG);
224 224 #define NUM2GIDT(v) NUM2LONG(v)
225 225 #endif
226 226
227   -#define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,1)
228   -#define FIX2ULONG(x) ((((VALUE)(x))>>1)&LONG_MAX)
229   -#define FIXNUM_P(f) (((SIGNED_VALUE)(f))&FIXNUM_FLAG)
  227 +#define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,2)
  228 +#define FIX2ULONG(x) ((((VALUE)(x))>>2)&LONG_MAX)
  229 +#define FIXNUM_P(f) ((((SIGNED_VALUE)(f)) & IMMEDIATE_MASK) == FIXNUM_FLAG)
230 230 #define POSFIXABLE(f) ((f) < FIXNUM_MAX+1)
231 231 #define NEGFIXABLE(f) ((f) >= FIXNUM_MIN)
232 232 #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
233 233
234 234 #define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK)
235 235
  236 +
  237 +#define VOODOO_DOUBLE(d) (*(VALUE*)(&d))
  238 +#define DBL2FIXFLOAT(d) (VOODOO_DOUBLE(d) | FIXFLOAT_FLAG)
  239 +#define FIXFLOAT_P(v) (((VALUE)v & IMMEDIATE_MASK) == FIXFLOAT_FLAG)
  240 +#define FIXFLOAT2DBL(v) coerce_ptr_to_double((VALUE)v)
  241 +
236 242 #if WITH_OBJC
237 243 # define SYMBOL_P(x) (TYPE(x) == T_SYMBOL)
238 244 # define ID2SYM(x) (rb_id2str((ID)x))
@@ -252,18 +258,29 @@ enum ruby_special_consts {
252 258
253 259 RUBY_IMMEDIATE_MASK = 0x03,
254 260 RUBY_FIXNUM_FLAG = 0x01,
  261 + RUBY_FIXFLOAT_FLAG = 0x03,
255 262 #if !WITH_OBJC
256 263 RUBY_SYMBOL_FLAG = 0x0e,
257 264 #endif
258 265 RUBY_SPECIAL_SHIFT = 8,
259 266 };
260 267
  268 +// We can't directly cast a void* to a double, so we cast it to a union
  269 +// and then extract its double member. Hacky, but effective.
  270 +static inline double coerce_ptr_to_double(VALUE v)
  271 +{
  272 + union {VALUE val; double d;} coerced_value;
  273 + coerced_value.val = v & ~RUBY_FIXFLOAT_FLAG; // unset the last two bits.
  274 + return coerced_value.d;
  275 +}
  276 +
261 277 #define Qfalse ((VALUE)RUBY_Qfalse)
262 278 #define Qtrue ((VALUE)RUBY_Qtrue)
263 279 #define Qnil ((VALUE)RUBY_Qnil)
264 280 #define Qundef ((VALUE)RUBY_Qundef) /* undefined value for placeholder */
265 281 #define IMMEDIATE_MASK RUBY_IMMEDIATE_MASK
266 282 #define FIXNUM_FLAG RUBY_FIXNUM_FLAG
  283 +#define FIXFLOAT_FLAG RUBY_FIXFLOAT_FLAG
267 284 #if !WITH_OBJC
268 285 # define SYMBOL_FLAG RUBY_SYMBOL_FLAG
269 286 #endif
@@ -536,7 +553,7 @@ struct RFloat {
536 553 struct RBasic basic;
537 554 double float_value;
538 555 };
539   -#define RFLOAT_VALUE(v) (RFLOAT(v)->float_value)
  556 +#define RFLOAT_VALUE(v) (FIXFLOAT_P(v) ? FIXFLOAT2DBL(v) : RFLOAT(v)->float_value)
540 557 #define DOUBLE2NUM(dbl) rb_float_new(dbl)
541 558
542 559 #if WITH_OBJC
@@ -1148,6 +1165,7 @@ rb_is_native(VALUE obj) {
1148 1165 #define CONDITION_TO_BOOLEAN(c) ((c) ? Qtrue : Qfalse)
1149 1166
1150 1167 VALUE rb_box_fixnum(VALUE);
  1168 +VALUE rb_box_fixfloat(VALUE);
1151 1169
1152 1170 static inline id
1153 1171 rb_rval_to_ocid(VALUE obj)
@@ -1162,9 +1180,12 @@ rb_rval_to_ocid(VALUE obj)
1162 1180 if (obj == Qnil) {
1163 1181 return (id)kCFNull;
1164 1182 }
1165   - if (FIXNUM_P(obj)) {
  1183 + if (FIXNUM_P(obj)) {
1166 1184 return (id)rb_box_fixnum(obj);
1167 1185 }
  1186 + if (FIXFLOAT_P(obj)) {
  1187 + return (id)rb_box_fixfloat(obj);
  1188 + }
1168 1189 }
1169 1190 return (id)obj;
1170 1191 }
@@ -1184,6 +1205,12 @@ rb_ocid_to_rval(id obj)
1184 1205 if (*(Class *)obj == (Class)rb_cFixnum) {
1185 1206 return LONG2FIX(RFIXNUM(obj)->value);
1186 1207 }
  1208 +#if 0 // XXX this does not seem to be needed
  1209 + if (*(Class *)obj == (Class)rb_cFloat) {
  1210 + extern VALUE rb_float_new(double);
  1211 + return rb_float_new(RFLOAT(obj)->float_value);
  1212 + }
  1213 +#endif
1187 1214 if (*(Class *)obj == (Class)rb_cCFNumber) {
1188 1215 /* TODO NSNumber should implement the Numeric primitive methods */
1189 1216 if (CFNumberIsFloatType((CFNumberRef)obj)) {
@@ -1217,6 +1244,7 @@ rb_class_of(VALUE obj)
1217 1244 {
1218 1245 if (IMMEDIATE_P(obj)) {
1219 1246 if (FIXNUM_P(obj)) return rb_cFixnum;
  1247 + if (FIXFLOAT_P(obj)) return rb_cFloat;
1220 1248 if (obj == Qtrue) return rb_cTrueClass;
1221 1249 #if !WITH_OBJC
1222 1250 if (SYMBOL_P(obj)) return rb_cSymbol;
@@ -1237,6 +1265,9 @@ rb_type(VALUE obj)
1237 1265 if (FIXNUM_P(obj)) {
1238 1266 return T_FIXNUM;
1239 1267 }
  1268 + if (FIXFLOAT_P(obj)) {
  1269 + return T_FLOAT;
  1270 + }
1240 1271 if (obj == Qtrue) {
1241 1272 return T_TRUE;
1242 1273 }
27 numeric.c
@@ -95,6 +95,21 @@ VALUE rb_eFloatDomainError;
95 95 static CFMutableDictionaryRef fixnum_dict = NULL;
96 96 static struct RFixnum *fixnum_cache = NULL;
97 97
  98 +static inline VALUE
  99 +rb_box_fixfloat0(double v)
  100 +{
  101 + NEWOBJ(val, struct RFloat);
  102 + OBJSETUP(val, rb_cFloat, T_FLOAT);
  103 + val->float_value = v;
  104 + return (VALUE)val;
  105 +}
  106 +
  107 +VALUE
  108 +rb_box_fixfloat(VALUE fixfloat)
  109 +{
  110 + return rb_box_fixfloat0(NUM2DBL(fixfloat));
  111 +}
  112 +
98 113 VALUE
99 114 rb_box_fixnum(VALUE fixnum)
100 115 {
@@ -533,12 +548,7 @@ num_to_int(VALUE num, SEL sel)
533 548 VALUE
534 549 rb_float_new(double d)
535 550 {
536   - NEWOBJ(flt, struct RFloat);
537   - OBJSETUP(flt, rb_cFloat, T_FLOAT);
538   -
539   - flt->float_value = d;
540   -
541   - return (VALUE)flt;
  551 + return DBL2FIXFLOAT(d);
542 552 }
543 553
544 554 /*
@@ -1379,7 +1389,6 @@ flo_truncate(VALUE num, SEL sel)
1379 1389 return LONG2FIX(val);
1380 1390 }
1381 1391
1382   -
1383 1392 /*
1384 1393 * call-seq:
1385 1394 * num.floor => integer
@@ -3136,6 +3145,8 @@ fix_even_p(VALUE num, SEL sel)
3136 3145 return Qtrue;
3137 3146 }
3138 3147
  3148 +
  3149 +
3139 3150 static const char *
3140 3151 imp_rb_float_objCType(void *rcv, SEL sel)
3141 3152 {
@@ -3384,6 +3395,6 @@ Init_Numeric(void)
3384 3395 rb_objc_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0);
3385 3396 rb_objc_define_method(rb_cFloat, "infinite?", flo_is_infinite_p, 0);
3386 3397 rb_objc_define_method(rb_cFloat, "finite?", flo_is_finite_p, 0);
3387   -
  3398 +
3388 3399 rb_install_nsnumber_primitives();
3389 3400 }
5 parse.y
@@ -8765,7 +8765,10 @@ negate_lit(NODE *node)
8765 8765 GC_WB(&node->nd_lit, rb_funcall(node->nd_lit,tUMINUS,0,0));
8766 8766 break;
8767 8767 case T_FLOAT:
8768   - RFLOAT(node->nd_lit)->float_value = -RFLOAT_VALUE(node->nd_lit);
  8768 + {
  8769 + double v = -RFLOAT_VALUE(node->nd_lit);
  8770 + node->nd_lit = DBL2FIXFLOAT(v);
  8771 + }
8769 8772 break;
8770 8773 default:
8771 8774 break;

0 comments on commit 01528a7

Please sign in to comment.
Something went wrong with that request. Please try again.