220 bool inline_string_copy(bool compress); |
220 bool inline_string_copy(bool compress); |
221 bool inline_string_char_access(bool is_store); |
221 bool inline_string_char_access(bool is_store); |
222 Node* round_double_node(Node* n); |
222 Node* round_double_node(Node* n); |
223 bool runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName); |
223 bool runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName); |
224 bool inline_math_native(vmIntrinsics::ID id); |
224 bool inline_math_native(vmIntrinsics::ID id); |
225 bool inline_trig(vmIntrinsics::ID id); |
|
226 bool inline_math(vmIntrinsics::ID id); |
225 bool inline_math(vmIntrinsics::ID id); |
227 template <typename OverflowOp> |
226 template <typename OverflowOp> |
228 bool inline_math_overflow(Node* arg1, Node* arg2); |
227 bool inline_math_overflow(Node* arg1, Node* arg2); |
229 void inline_math_mathExact(Node* math, Node* test); |
228 void inline_math_mathExact(Node* math, Node* test); |
230 bool inline_math_addExactI(bool is_increment); |
229 bool inline_math_addExactI(bool is_increment); |
1686 case vmIntrinsics::_dabs: n = new AbsDNode( arg); break; |
1685 case vmIntrinsics::_dabs: n = new AbsDNode( arg); break; |
1687 case vmIntrinsics::_dsqrt: n = new SqrtDNode(C, control(), arg); break; |
1686 case vmIntrinsics::_dsqrt: n = new SqrtDNode(C, control(), arg); break; |
1688 default: fatal_unexpected_iid(id); break; |
1687 default: fatal_unexpected_iid(id); break; |
1689 } |
1688 } |
1690 set_result(_gvn.transform(n)); |
1689 set_result(_gvn.transform(n)); |
1691 return true; |
|
1692 } |
|
1693 |
|
1694 //------------------------------inline_trig---------------------------------- |
|
1695 // Inline sin/cos/tan instructions, if possible. If rounding is required, do |
|
1696 // argument reduction which will turn into a fast/slow diamond. |
|
1697 bool LibraryCallKit::inline_trig(vmIntrinsics::ID id) { |
|
1698 Node* arg = round_double_node(argument(0)); |
|
1699 Node* n = NULL; |
|
1700 |
|
1701 n = _gvn.transform(n); |
|
1702 |
|
1703 // Rounding required? Check for argument reduction! |
|
1704 if (Matcher::strict_fp_requires_explicit_rounding) { |
|
1705 static const double pi_4 = 0.7853981633974483; |
|
1706 static const double neg_pi_4 = -0.7853981633974483; |
|
1707 // pi/2 in 80-bit extended precision |
|
1708 // static const unsigned char pi_2_bits_x[] = {0x35,0xc2,0x68,0x21,0xa2,0xda,0x0f,0xc9,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00}; |
|
1709 // -pi/2 in 80-bit extended precision |
|
1710 // static const unsigned char neg_pi_2_bits_x[] = {0x35,0xc2,0x68,0x21,0xa2,0xda,0x0f,0xc9,0xff,0xbf,0x00,0x00,0x00,0x00,0x00,0x00}; |
|
1711 // Cutoff value for using this argument reduction technique |
|
1712 //static const double pi_2_minus_epsilon = 1.564660403643354; |
|
1713 //static const double neg_pi_2_plus_epsilon = -1.564660403643354; |
|
1714 |
|
1715 // Pseudocode for sin: |
|
1716 // if (x <= Math.PI / 4.0) { |
|
1717 // if (x >= -Math.PI / 4.0) return fsin(x); |
|
1718 // if (x >= -Math.PI / 2.0) return -fcos(x + Math.PI / 2.0); |
|
1719 // } else { |
|
1720 // if (x <= Math.PI / 2.0) return fcos(x - Math.PI / 2.0); |
|
1721 // } |
|
1722 // return StrictMath.sin(x); |
|
1723 |
|
1724 // Pseudocode for cos: |
|
1725 // if (x <= Math.PI / 4.0) { |
|
1726 // if (x >= -Math.PI / 4.0) return fcos(x); |
|
1727 // if (x >= -Math.PI / 2.0) return fsin(x + Math.PI / 2.0); |
|
1728 // } else { |
|
1729 // if (x <= Math.PI / 2.0) return -fsin(x - Math.PI / 2.0); |
|
1730 // } |
|
1731 // return StrictMath.cos(x); |
|
1732 |
|
1733 // Actually, sticking in an 80-bit Intel value into C2 will be tough; it |
|
1734 // requires a special machine instruction to load it. Instead we'll try |
|
1735 // the 'easy' case. If we really need the extra range +/- PI/2 we'll |
|
1736 // probably do the math inside the SIN encoding. |
|
1737 |
|
1738 // Make the merge point |
|
1739 RegionNode* r = new RegionNode(3); |
|
1740 Node* phi = new PhiNode(r, Type::DOUBLE); |
|
1741 |
|
1742 // Flatten arg so we need only 1 test |
|
1743 Node *abs = _gvn.transform(new AbsDNode(arg)); |
|
1744 // Node for PI/4 constant |
|
1745 Node *pi4 = makecon(TypeD::make(pi_4)); |
|
1746 // Check PI/4 : abs(arg) |
|
1747 Node *cmp = _gvn.transform(new CmpDNode(pi4,abs)); |
|
1748 // Check: If PI/4 < abs(arg) then go slow |
|
1749 Node *bol = _gvn.transform(new BoolNode( cmp, BoolTest::lt )); |
|
1750 // Branch either way |
|
1751 IfNode *iff = create_and_xform_if(control(),bol, PROB_STATIC_FREQUENT, COUNT_UNKNOWN); |
|
1752 set_control(opt_iff(r,iff)); |
|
1753 |
|
1754 // Set fast path result |
|
1755 phi->init_req(2, n); |
|
1756 |
|
1757 // Slow path - non-blocking leaf call |
|
1758 Node* call = NULL; |
|
1759 switch (id) { |
|
1760 case vmIntrinsics::_dtan: |
|
1761 call = make_runtime_call(RC_LEAF, OptoRuntime::Math_D_D_Type(), |
|
1762 CAST_FROM_FN_PTR(address, SharedRuntime::dtan), |
|
1763 "Tan", NULL, arg, top()); |
|
1764 break; |
|
1765 } |
|
1766 assert(control()->in(0) == call, ""); |
|
1767 Node* slow_result = _gvn.transform(new ProjNode(call, TypeFunc::Parms)); |
|
1768 r->init_req(1, control()); |
|
1769 phi->init_req(1, slow_result); |
|
1770 |
|
1771 // Post-merge |
|
1772 set_control(_gvn.transform(r)); |
|
1773 record_for_igvn(r); |
|
1774 n = _gvn.transform(phi); |
|
1775 |
|
1776 C->set_has_split_ifs(true); // Has chance for split-if optimization |
|
1777 } |
|
1778 set_result(n); |
|
1779 return true; |
1690 return true; |
1780 } |
1691 } |
1781 |
1692 |
1782 //------------------------------runtime_math----------------------------- |
1693 //------------------------------runtime_math----------------------------- |
1783 bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName) { |
1694 bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName) { |