diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index bb30dcb2976a7..792ba54c76b18 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -2357,3 +2357,301 @@ bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeO return true; } + +uint PureCallNode::size_of() const { return sizeof(*this); } +bool PureCallNode::cmp(const Node& n) const { + const PureCallNode& call = static_cast(n); + return Opcode() == call.Opcode() && _tf->eq(call._tf) && _addr == call._addr && _name == call._name; +} +uint PureCallNode::hash() const { + return Node::hash() + _tf->hash() + reinterpret_cast(_addr) + reinterpret_cast(_name); +} +PureCallNode::PureCallNode(Compile* C, uint required, const TypeFunc* tf, address addr, const char* name) : Node(required) { + init_class_id(Class_PureCall); + add_flag(Flag_is_macro); + C->add_macro_node(this); + _tf = tf; + _addr = addr; + _name = name; +} +PureFloatingModuloNode::PureFloatingModuloNode(Compile* C, uint required, const TypeFunc* tf, address addr, const char* name) + : PureCallNode(C, required, tf, addr, name) { + init_class_id(Class_PureFloatingModulo); +} +PureModFNode::PureModFNode(Compile* C, Node* ctrl, Node* lhs, Node* rhs) + : PureFloatingModuloNode(C, 3, OptoRuntime::modf_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::frem), "frem") { + init_class_id(Class_PureModF); +} +PureModDNode::PureModDNode(Compile* C, Node* ctrl, Node* lhs, Node* rhs) + : PureFloatingModuloNode(C, 5, OptoRuntime::Math_DD_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::drem), "drem") { + init_class_id(Class_PureModF); +} +PureModFNode* PureModFNode::make(Compile* C, Node* ctrl, Node* lhs, Node* rhs) { + auto* node = new PureModFNode(C, ctrl, lhs, rhs); + node->init_req(Control, ctrl); + node->init_req(Parms, lhs); + node->init_req(Parms + 1, rhs); + return node; +} +PureModDNode* PureModDNode::make(Compile* C, Node* ctrl, Node* lhs, Node* rhs) { + auto* node = new PureModDNode(C, ctrl, lhs, rhs); + node->init_req(Control, ctrl); + node->init_req(Parms, lhs); + node->init_req(Parms + 1, C->top()); + node->init_req(Parms + 2, rhs); + node->init_req(Parms + 3, C->top()); + return node; +} + +ProjNode* PureCallNode::proj_out_or_null(uint which_proj) const { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + Node* p = fast_out(i); + if (p->is_Proj()) { + ProjNode* proj = p->as_Proj(); + if (proj->_con == which_proj) { + return proj; + } + } else { + assert(p == this && is_Start(), "else must be proj"); + continue; + } + } + return nullptr; +} + +void PureCallNode::extract_projections(Node*& ctrl_proj, Node*& data_proj) const { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + ProjNode* pn = fast_out(i)->as_Proj(); + if (pn->outcnt() == 0) { + continue; + } + switch (pn->_con) { + case TypeFunc::Control: + ctrl_proj = pn; + break; + case TypeFunc::Parms: + data_proj = pn; + break; + default: + assert(false, "unexpected projection type for a pure function"); + } + } +} + +void PureCallNode::replace_with_con(PhaseIterGVN* phase, const Type* con) { + Compile* C = phase->C; + Node* con_node = phase->makecon(con); + Node* ctrl_proj = nullptr; + Node* data_proj = nullptr; + extract_projections(ctrl_proj, data_proj); + if (ctrl_proj == nullptr) { + return; + } + phase->replace_node(ctrl_proj, in(Control)); + if (data_proj != nullptr) { + phase->replace_node(data_proj, con_node); + } + phase->replace_node(this, C->top()); + C->remove_macro_node(this); +} + +void PureCallNode::remove_unused_node(PhaseIterGVN* phase) { + Compile* C = phase->C; + Node* ctrl_proj = nullptr; + Node* data_proj = nullptr; + extract_projections(ctrl_proj, data_proj); + assert(data_proj == nullptr, "result is not unused"); + if (ctrl_proj == nullptr) { + return; + } + phase->replace_node(ctrl_proj, in(Control)); + phase->replace_node(this, C->top()); + C->remove_macro_node(this); +} + +Node* PureCallNode::expand_macro(Compile* C) const { + CallNode* call = new CallLeafNode(tf(), addr(), name(), TypeRawPtr::BOTTOM); + call->init_req(TypeFunc::Control, in(Control)); + call->init_req(TypeFunc::I_O, C->top()); + call->init_req(TypeFunc::Memory, C->top()); + call->init_req(TypeFunc::ReturnAdr, C->top()); + call->init_req(TypeFunc::FramePtr, C->top()); + for (uint i = 0; i < tf()->domain()->cnt() - TypeFunc::Parms; i++) { + call->init_req(TypeFunc::Parms + i, in(Parms + i)); + } + return call; +} + +const Type* PureCallNode::bottom_type() const { + return tf()->range(); +} +const Type* PureCallNode::Value(PhaseGVN* phase) const { + if (in(0) == nullptr || phase->type(in(0)) == Type::TOP) { + return Type::TOP; + } + return bottom_type(); +} +bool PureCallNode::remove_if_result_is_unused(PhaseIterGVN* igvn) { + bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; + bool not_dead = proj_out_or_null(TypeFunc::Control) != nullptr; + if (result_is_unused && not_dead) { + remove_unused_node(igvn); + return true; + } + return false; +} +Node* PureCallNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (!can_reshape) { + return nullptr; + } + + remove_if_result_is_unused(phase->is_IterGVN()); + return nullptr; +} + +#ifndef PRODUCT +void PureCallNode::dump_spec(outputStream* st) const { + st->print("# %s", name()); +} +#endif + +Node* PureModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (!can_reshape) { + return nullptr; + } + PhaseIterGVN* igvn = phase->is_IterGVN(); + + if (remove_if_result_is_unused(igvn)) { + return nullptr; + } + + // Either input is TOP ==> the result is TOP + const Type* t1 = phase->type(dividend()); + const Type* t2 = phase->type(divisor()); + if (t1 == Type::TOP || t2 == Type::TOP) { + return phase->C->top(); + } + + // If either number is not a constant, we know nothing. + if ((t1->base() != Type::FloatCon) || (t2->base() != Type::FloatCon)) { + return nullptr; // note: x%x can be either NaN or 0 + } + + float f1 = t1->getf(); + float f2 = t2->getf(); + jint x1 = jint_cast(f1); // note: *(int*)&f1, not just (int)f1 + jint x2 = jint_cast(f2); + + // If either is a NaN, return an input NaN + if (g_isnan(f1)) { + replace_with_con(igvn, t1); + return nullptr; + } + if (g_isnan(f2)) { + replace_with_con(igvn, t2); + return nullptr; + } + + // If an operand is infinity or the divisor is +/- zero, punt. + if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jint) { + return nullptr; + } + + // We must be modulo'ing 2 float constants. + // Make sure that the sign of the fmod is equal to the sign of the dividend + jint xr = jint_cast(fmod(f1, f2)); + if ((x1 ^ xr) < 0) { + xr ^= min_jint; + } + + replace_with_con(igvn, TypeF::make(jfloat_cast(xr))); + return nullptr; +} + +Node* PureModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (!can_reshape) { + return nullptr; + } + PhaseIterGVN* igvn = phase->is_IterGVN(); + + if (remove_if_result_is_unused(igvn)) { + return nullptr; + } + + // Either input is TOP ==> the result is TOP + const Type* t1 = phase->type(dividend()); + const Type* t2 = phase->type(divisor()); + if (t1 == Type::TOP || t2 == Type::TOP) { + return nullptr; + } + + // If either number is not a constant, we know nothing. + if ((t1->base() != Type::DoubleCon) || (t2->base() != Type::DoubleCon)) { + return nullptr; // note: x%x can be either NaN or 0 + } + + double f1 = t1->getd(); + double f2 = t2->getd(); + jlong x1 = jlong_cast(f1); // note: *(long*)&f1, not just (long)f1 + jlong x2 = jlong_cast(f2); + + // If either is a NaN, return an input NaN + if (g_isnan(f1)) { + replace_with_con(igvn, t1); + return nullptr; + } + if (g_isnan(f2)) { + replace_with_con(igvn, t2); + return nullptr; + } + + // If an operand is infinity or the divisor is +/- zero, punt. + if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jlong) { + return nullptr; + } + + // We must be modulo'ing 2 double constants. + // Make sure that the sign of the fmod is equal to the sign of the dividend + jlong xr = jlong_cast(fmod(f1, f2)); + if ((x1 ^ xr) < 0) { + xr ^= min_jlong; + } + + replace_with_con(igvn, TypeD::make(jdouble_cast(xr))); + return nullptr; +} + +Node* PureModFNode::dividend() const { return in(Parms); } +Node* PureModFNode::divisor() const { return in(Parms + 1); } +Node* PureModDNode::dividend() const { return in(Parms); } +Node* PureModDNode::divisor() const { return in(Parms + 2); } + +PureNativeMathNode::PureNativeMathNode(Compile* C, uint required, const TypeFunc* tf, address addr, const char* name) + : PureCallNode(C, required, tf, addr, name) { + init_class_id(Class_PureNativeMath); +} +PureUnaryNativeMathNode::PureUnaryNativeMathNode(Compile* C, address addr, const char* name) + : PureNativeMathNode(C, 3, OptoRuntime::Math_D_D_Type(), addr, name) { + init_class_id(Class_PureUnaryNativeMath); +} +PureBinaryNativeMathNode::PureBinaryNativeMathNode(Compile* C, address addr, const char* name) + : PureNativeMathNode(C, 5, OptoRuntime::Math_DD_D_Type(), addr, name) { + init_class_id(Class_PureBinaryNativeMath); +} + +PureUnaryNativeMathNode* PureUnaryNativeMathNode::make(Compile* C, address addr, const char* name, Node* ctrl, Node* arg) { + auto* node = new PureUnaryNativeMathNode(C, addr, name); + node->init_req(Control, ctrl); + node->init_req(Parms, arg); + node->init_req(Parms + 1, C->top()); + return node; +} +PureBinaryNativeMathNode* PureBinaryNativeMathNode::make(Compile* C, address addr, const char* name, Node* ctrl, Node* lhs, Node* rhs) { + auto* node = new PureBinaryNativeMathNode(C, addr, name); + node->init_req(Control, ctrl); + node->init_req(Parms, lhs); + node->init_req(Parms + 1, C->top()); + node->init_req(Parms + 2, rhs); + node->init_req(Parms + 3, C->top()); + return node; +} diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index db857d4c6d1a6..939a0c0ba7dab 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -55,6 +55,13 @@ class AbstractLockNode; class LockNode; class UnlockNode; class FastLockNode; +class PureCallNode; +class PureFloatingModuloNode; +class PureModFNode; +class PureModDNode; +class PureNativeMathNode; +class PureUnaryNativeMathNode; +class PureBinaryNativeMathNode; //------------------------------StartNode-------------------------------------- // The method start node @@ -1262,4 +1269,102 @@ class UnlockNode : public AbstractLockNode { JVMState* dbg_jvms() const { return nullptr; } #endif }; + +//------------------------------PureCall----------------------------------- +class PureCallNode : public Node { + uint size_of() const override; // Size is bigger + bool cmp(const Node& n) const override; + uint hash() const override; + +protected: + const TypeFunc* _tf; + address _addr; + const char* _name; + + PureCallNode(Compile* C, uint required, const TypeFunc* tf, address addr, const char* name); + + bool remove_if_result_is_unused(PhaseIterGVN* phase); + +public: + enum { + Control = 0, + Parms = 1, + }; + + int Opcode() const override; + + const Type* bottom_type() const override; + const Type* Value(PhaseGVN* phase) const override; + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + Node* Identity(PhaseGVN* phase) override { return this; } + + const TypeFunc* tf() const { return _tf; } + address addr() const { return _addr; } + const char* name() const { return _name; } + bool is_CFG() const override { return true; } + bool depends_only_on_test() const override { return false; } + + ProjNode* proj_out_or_null(uint which_proj) const; + void remove_unused_node(PhaseIterGVN* phase); + void replace_with_con(PhaseIterGVN* phase, const Type* con); + void extract_projections(Node*& ctrl_proj, Node*& data_proj) const; + + Node* expand_macro(Compile* C) const; + + NOT_PRODUCT(void dump_spec(outputStream* st) const override;) +}; + +class PureFloatingModuloNode : public PureCallNode { +protected: + PureFloatingModuloNode(Compile* C, uint required, const TypeFunc* tf, address addr, const char* name); + virtual Node* dividend() const = 0; + virtual Node* divisor() const = 0; + +public: + virtual int Opcode() const; +}; + +class PureModFNode : public PureFloatingModuloNode { + PureModFNode(Compile* C, Node* ctrl, Node* lhs, Node* rhs); + Node* dividend() const override; + Node* divisor() const override; + +public: + static PureModFNode* make(Compile* C, Node* ctrl, Node* lhs, Node* rhs); + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + int Opcode() const override; +}; +class PureModDNode : public PureFloatingModuloNode { + PureModDNode(Compile* C, Node* ctrl, Node* lhs, Node* rhs); + Node* dividend() const override; + Node* divisor() const override; + +public: + static PureModDNode* make(Compile* C, Node* ctrl, Node* lhs, Node* rhs); + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + int Opcode() const override; +}; +class PureNativeMathNode : public PureCallNode { +protected: + PureNativeMathNode(Compile* C, uint required, const TypeFunc* tf, address addr, const char* name); + +public: + int Opcode() const override; +}; +class PureUnaryNativeMathNode : public PureNativeMathNode { +protected: + PureUnaryNativeMathNode(Compile* C, address addr, const char* name); + +public: + int Opcode() const override; + static PureUnaryNativeMathNode* make(Compile* C, address addr, const char* name, Node* ctrl, Node* arg); +}; +class PureBinaryNativeMathNode : public PureNativeMathNode { +protected: + PureBinaryNativeMathNode(Compile* C, address addr, const char* name); + +public: + int Opcode() const override; + static PureBinaryNativeMathNode* make(Compile* C, address addr, const char* name, Node* ctrl, Node* lhs, Node* rhs); +}; #endif // SHARE_OPTO_CALLNODE_HPP diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index bc259eed2d101..16032d36a4ce1 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -246,8 +246,6 @@ macro(MinL) macro(MinHF) macro(MinF) macro(MinD) -macro(ModD) -macro(ModF) macro(ModI) macro(ModL) macro(UModI) @@ -304,6 +302,13 @@ macro(PopCountVL) macro(PopulateIndex) macro(PrefetchAllocation) macro(Proj) +macro(PureBinaryNativeMath) +macro(PureCall) +macro(PureFloatingModulo) +macro(PureModD) +macro(PureModF) +macro(PureNativeMath) +macro(PureUnaryNativeMath) macro(RShiftI) macro(RShiftL) macro(Region) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e4e82cbddabeb..3c9329171c38e 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3238,7 +3238,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f case Op_MulF: case Op_DivF: case Op_NegF: - case Op_ModF: case Op_ConvI2F: case Op_ConF: case Op_CmpF: @@ -3261,7 +3260,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f case Op_MulD: case Op_DivD: case Op_NegD: - case Op_ModD: case Op_ConvI2D: case Op_ConvD2I: // case Op_ConvL2D: // handled by leaf call @@ -3282,7 +3280,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f case Op_CallDynamicJava: frc.inc_java_call_count(); // Count java call site; case Op_CallRuntime: - case Op_CallLeaf: + case Op_CallLeaf: // including expanded PureCallNode case Op_CallLeafVector: case Op_CallLeafNoFP: { assert (n->is_Call(), ""); diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index a70194274a793..f09643c95c925 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -42,23 +42,6 @@ #include -ModFloatingNode::ModFloatingNode(Compile* C, const TypeFunc* tf, const char* name) : CallLeafNode(tf, nullptr, name, TypeRawPtr::BOTTOM) { - add_flag(Flag_is_macro); - C->add_macro_node(this); -} - -ModDNode::ModDNode(Compile* C, Node* a, Node* b) : ModFloatingNode(C, OptoRuntime::Math_DD_D_Type(), "drem") { - init_req(TypeFunc::Parms + 0, a); - init_req(TypeFunc::Parms + 1, C->top()); - init_req(TypeFunc::Parms + 2, b); - init_req(TypeFunc::Parms + 3, C->top()); -} - -ModFNode::ModFNode(Compile* C, Node* a, Node* b) : ModFloatingNode(C, OptoRuntime::modf_Type(), "frem") { - init_req(TypeFunc::Parms + 0, a); - init_req(TypeFunc::Parms + 1, b); -} - //----------------------magic_int_divide_constants----------------------------- // Compute magic multiplier and shift constant for converting a 32 bit divide // by constant into a multiply/shift/add series. Return false if calculations @@ -1516,139 +1499,6 @@ const Type* UModLNode::Value(PhaseGVN* phase) const { return unsigned_mod_value(phase, this); } -Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (!can_reshape) { - return nullptr; - } - PhaseIterGVN* igvn = phase->is_IterGVN(); - - bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; - bool not_dead = proj_out_or_null(TypeFunc::Control) != nullptr; - if (result_is_unused && not_dead) { - return replace_with_con(igvn, TypeF::make(0.)); - } - - // Either input is TOP ==> the result is TOP - const Type* t1 = phase->type(dividend()); - const Type* t2 = phase->type(divisor()); - if (t1 == Type::TOP || t2 == Type::TOP) { - return phase->C->top(); - } - - // If either number is not a constant, we know nothing. - if ((t1->base() != Type::FloatCon) || (t2->base() != Type::FloatCon)) { - return nullptr; // note: x%x can be either NaN or 0 - } - - float f1 = t1->getf(); - float f2 = t2->getf(); - jint x1 = jint_cast(f1); // note: *(int*)&f1, not just (int)f1 - jint x2 = jint_cast(f2); - - // If either is a NaN, return an input NaN - if (g_isnan(f1)) { - return replace_with_con(igvn, t1); - } - if (g_isnan(f2)) { - return replace_with_con(igvn, t2); - } - - // If an operand is infinity or the divisor is +/- zero, punt. - if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jint) { - return nullptr; - } - - // We must be modulo'ing 2 float constants. - // Make sure that the sign of the fmod is equal to the sign of the dividend - jint xr = jint_cast(fmod(f1, f2)); - if ((x1 ^ xr) < 0) { - xr ^= min_jint; - } - - return replace_with_con(igvn, TypeF::make(jfloat_cast(xr))); -} - -Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (!can_reshape) { - return nullptr; - } - PhaseIterGVN* igvn = phase->is_IterGVN(); - - bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; - bool not_dead = proj_out_or_null(TypeFunc::Control) != nullptr; - if (result_is_unused && not_dead) { - return replace_with_con(igvn, TypeD::make(0.)); - } - - // Either input is TOP ==> the result is TOP - const Type* t1 = phase->type(dividend()); - const Type* t2 = phase->type(divisor()); - if (t1 == Type::TOP || t2 == Type::TOP) { - return nullptr; - } - - // If either number is not a constant, we know nothing. - if ((t1->base() != Type::DoubleCon) || (t2->base() != Type::DoubleCon)) { - return nullptr; // note: x%x can be either NaN or 0 - } - - double f1 = t1->getd(); - double f2 = t2->getd(); - jlong x1 = jlong_cast(f1); // note: *(long*)&f1, not just (long)f1 - jlong x2 = jlong_cast(f2); - - // If either is a NaN, return an input NaN - if (g_isnan(f1)) { - return replace_with_con(igvn, t1); - } - if (g_isnan(f2)) { - return replace_with_con(igvn, t2); - } - - // If an operand is infinity or the divisor is +/- zero, punt. - if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jlong) { - return nullptr; - } - - // We must be modulo'ing 2 double constants. - // Make sure that the sign of the fmod is equal to the sign of the dividend - jlong xr = jlong_cast(fmod(f1, f2)); - if ((x1 ^ xr) < 0) { - xr ^= min_jlong; - } - - return replace_with_con(igvn, TypeD::make(jdouble_cast(xr))); -} - -Node* ModFloatingNode::replace_with_con(PhaseIterGVN* phase, const Type* con) { - Compile* C = phase->C; - Node* con_node = phase->makecon(con); - CallProjections projs; - extract_projections(&projs, false, false); - phase->replace_node(projs.fallthrough_proj, in(TypeFunc::Control)); - if (projs.fallthrough_catchproj != nullptr) { - phase->replace_node(projs.fallthrough_catchproj, in(TypeFunc::Control)); - } - if (projs.fallthrough_memproj != nullptr) { - phase->replace_node(projs.fallthrough_memproj, in(TypeFunc::Memory)); - } - if (projs.catchall_memproj != nullptr) { - phase->replace_node(projs.catchall_memproj, C->top()); - } - if (projs.fallthrough_ioproj != nullptr) { - phase->replace_node(projs.fallthrough_ioproj, in(TypeFunc::I_O)); - } - assert(projs.catchall_ioproj == nullptr, "no exceptions from floating mod"); - assert(projs.catchall_catchproj == nullptr, "no exceptions from floating mod"); - if (projs.resproj != nullptr) { - phase->replace_node(projs.resproj, con_node); - } - phase->replace_node(this, C->top()); - C->remove_macro_node(this); - disconnect_inputs(C); - return nullptr; -} - //============================================================================= DivModNode::DivModNode( Node *c, Node *dividend, Node *divisor ) : MultiNode(3) { diff --git a/src/hotspot/share/opto/divnode.hpp b/src/hotspot/share/opto/divnode.hpp index 127e2431b0b3b..065fbb98c62d1 100644 --- a/src/hotspot/share/opto/divnode.hpp +++ b/src/hotspot/share/opto/divnode.hpp @@ -155,43 +155,6 @@ class ModLNode : public Node { virtual uint ideal_reg() const { return Op_RegL; } }; -// Base class for float and double modulus -class ModFloatingNode : public CallLeafNode { -protected: - Node* replace_with_con(PhaseIterGVN* phase, const Type* con); - -public: - ModFloatingNode(Compile* C, const TypeFunc* tf, const char *name); -}; - -// Float Modulus -class ModFNode : public ModFloatingNode { -private: - Node* dividend() const { return in(TypeFunc::Parms + 0); } - Node* divisor() const { return in(TypeFunc::Parms + 1); } - -public: - ModFNode(Compile* C, Node* a, Node* b); - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegF; } - virtual uint size_of() const { return sizeof(*this); } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); -}; - -// Double Modulus -class ModDNode : public ModFloatingNode { -private: - Node* dividend() const { return in(TypeFunc::Parms + 0); } - Node* divisor() const { return in(TypeFunc::Parms + 2); } - -public: - ModDNode(Compile* C, Node* a, Node* b); - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegD; } - virtual uint size_of() const { return sizeof(*this); } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); -}; - //------------------------------UModINode--------------------------------------- // Unsigned integer modulus class UModINode : public Node { diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 017564173a847..f5873523ed53c 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1787,21 +1787,18 @@ bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, c assert(call_type == OptoRuntime::Math_DD_D_Type() || call_type == OptoRuntime::Math_D_D_Type(), "must be (DD)D or (D)D type"); - // Inputs - Node* a = argument(0); - Node* b = (call_type == OptoRuntime::Math_DD_D_Type()) ? argument(2) : nullptr; + Node* lhs = argument(0); - const TypePtr* no_memory_effects = nullptr; - Node* trig = make_runtime_call(RC_LEAF, call_type, funcAddr, funcName, - no_memory_effects, - a, top(), b, b ? top() : nullptr); - Node* value = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+0)); -#ifdef ASSERT - Node* value_top = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+1)); - assert(value_top == top(), "second value must be top"); -#endif - - set_result(value); + Node* call; + if (call_type == OptoRuntime::Math_DD_D_Type()) { + Node* rhs = argument(2); + call = PureBinaryNativeMathNode::make(C, funcAddr, funcName, control(), lhs, rhs); + } else { + call = PureUnaryNativeMathNode::make(C, funcAddr, funcName, control(), lhs); + } + call = _gvn.transform(call); + set_control(_gvn.transform(new ProjNode(call, TypeFunc::Control))); + set_result(_gvn.transform(new ProjNode(call, TypeFunc::Parms + 0))); return true; } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index c3f411eea9436..925d9e92dbdc5 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -221,7 +221,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) { if (nb_ctl_proj > 1) { break; } - assert(parent_ctl->is_Start() || parent_ctl->is_MemBar() || parent_ctl->is_Call() || + assert(parent_ctl->is_Start() || parent_ctl->is_MemBar() || parent_ctl->is_Call() || parent_ctl->is_PureCall() || BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(parent_ctl), "unexpected node"); assert(idom(ctl) == parent_ctl, "strange"); next = idom(parent_ctl); diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 1bd35f9dcc980..1ca4182364666 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2433,8 +2433,7 @@ void PhaseMacroExpand::eliminate_macro_nodes() { break; default: assert(n->Opcode() == Op_LoopLimit || - n->Opcode() == Op_ModD || - n->Opcode() == Op_ModF || + n->is_PureCall() || n->is_OpaqueNotNull() || n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || @@ -2586,28 +2585,13 @@ bool PhaseMacroExpand::expand_macro_nodes() { expand_subtypecheck_node(n->as_SubTypeCheck()); break; default: - switch (n->Opcode()) { - case Op_ModD: - case Op_ModF: { - bool is_drem = n->Opcode() == Op_ModD; - CallNode* mod_macro = n->as_Call(); - CallNode* call = new CallLeafNode(mod_macro->tf(), - is_drem ? CAST_FROM_FN_PTR(address, SharedRuntime::drem) - : CAST_FROM_FN_PTR(address, SharedRuntime::frem), - is_drem ? "drem" : "frem", TypeRawPtr::BOTTOM); - call->init_req(TypeFunc::Control, mod_macro->in(TypeFunc::Control)); - call->init_req(TypeFunc::I_O, mod_macro->in(TypeFunc::I_O)); - call->init_req(TypeFunc::Memory, mod_macro->in(TypeFunc::Memory)); - call->init_req(TypeFunc::ReturnAdr, mod_macro->in(TypeFunc::ReturnAdr)); - call->init_req(TypeFunc::FramePtr, mod_macro->in(TypeFunc::FramePtr)); - for (unsigned int i = 0; i < mod_macro->tf()->domain()->cnt() - TypeFunc::Parms; i++) { - call->init_req(TypeFunc::Parms + i, mod_macro->in(TypeFunc::Parms + i)); - } - _igvn.replace_node(mod_macro, call); - transform_later(call); + if (n->is_PureCall()) { + PureCallNode* pure_call = n->as_PureCall(); + Node* new_node = pure_call->expand_macro(C); + _igvn.replace_node(pure_call, new_node); + transform_later(new_node); break; - } - default: + } else { assert(false, "unknown node type in macro list"); } } diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 76e193609101c..07caa8e22531e 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -2935,13 +2935,7 @@ bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); } bool Node::is_pure_function() const { - switch (Opcode()) { - case Op_ModD: - case Op_ModF: - return true; - default: - return false; - } + return is_PureCall(); } // `maybe_pure_function` is assumed to be the input of `this`. This is a bit redundant, diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 1cb9009ef276b..7ff83fae52f34 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -164,6 +164,13 @@ class PhiNode; class Pipeline; class PopulateIndexNode; class ProjNode; +class PureBinaryNativeMathNode; +class PureCallNode; +class PureFloatingModuloNode; +class PureModDNode; +class PureModFNode; +class PureNativeMathNode; +class PureUnaryNativeMathNode; class RangeCheckNode; class ReductionNode; class RegMask; @@ -811,6 +818,13 @@ class Node { DEFINE_CLASS_ID(Move, Node, 20) DEFINE_CLASS_ID(LShift, Node, 21) DEFINE_CLASS_ID(Neg, Node, 22) + DEFINE_CLASS_ID(PureCall, Node, 23) + DEFINE_CLASS_ID(PureFloatingModulo, PureCall, 0) + DEFINE_CLASS_ID(PureModF, PureFloatingModulo, 0) + DEFINE_CLASS_ID(PureModD, PureFloatingModulo, 1) + DEFINE_CLASS_ID(PureNativeMath, PureCall, 1) + DEFINE_CLASS_ID(PureUnaryNativeMath, PureNativeMath, 0) + DEFINE_CLASS_ID(PureBinaryNativeMath, PureNativeMath, 1) _max_classes = ClassMask_Neg }; @@ -996,6 +1010,13 @@ class Node { DEFINE_CLASS_QUERY(PCTable) DEFINE_CLASS_QUERY(Phi) DEFINE_CLASS_QUERY(Proj) + DEFINE_CLASS_QUERY(PureBinaryNativeMath) + DEFINE_CLASS_QUERY(PureCall) + DEFINE_CLASS_QUERY(PureFloatingModulo) + DEFINE_CLASS_QUERY(PureModD) + DEFINE_CLASS_QUERY(PureModF) + DEFINE_CLASS_QUERY(PureNativeMath) + DEFINE_CLASS_QUERY(PureUnaryNativeMath) DEFINE_CLASS_QUERY(Reduction) DEFINE_CLASS_QUERY(Region) DEFINE_CLASS_QUERY(Root) diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 1a4c3c91c4f08..5b7d26169a03e 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1097,13 +1097,17 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, Node* Parse::floating_point_mod(Node* a, Node* b, BasicType type) { assert(type == BasicType::T_FLOAT || type == BasicType::T_DOUBLE, "only float and double are floating points"); - CallNode* mod = type == BasicType::T_DOUBLE ? static_cast(new ModDNode(C, a, b)) : new ModFNode(C, a, b); + PureCallNode* call; + if (type == T_DOUBLE) { + call = PureModDNode::make(C, control(), a, b); + } else { + call = PureModFNode::make(C, control(), a, b); + } - Node* prev_mem = set_predefined_input_for_runtime_call(mod); - mod = _gvn.transform(mod)->as_Call(); - set_predefined_output_for_runtime_call(mod, prev_mem, TypeRawPtr::BOTTOM); - Node* result = _gvn.transform(new ProjNode(mod, TypeFunc::Parms + 0)); - record_for_igvn(mod); + call = _gvn.transform(call)->as_PureCall(); + set_control(_gvn.transform(new ProjNode(call, TypeFunc::Control))); + Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms + 0)); + record_for_igvn(call); return result; } diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 9c40e1ab3cdd7..7e3bf53e775d4 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1928,8 +1928,10 @@ class TypeNarrowKlass : public TypeNarrowPtr { // Class of Array Types class TypeFunc : public Type { TypeFunc( const TypeTuple *domain, const TypeTuple *range ) : Type(Function), _domain(domain), _range(range) {} +public: virtual bool eq( const Type *t ) const; virtual uint hash() const; // Type specific hashing +private: virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter index f94f06ab28454..9503e0f55c26a 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/customNodeInfo.filter @@ -28,6 +28,8 @@ function callLeafInfo(dump_spec, pos) { } editProperty(matches("name", "CallLeaf|CallLeafNoFP"), ["dump_spec"], "extra_label", function(dump_spec) {return callLeafInfo(dump_spec[0], 1);}); +editProperty(matches("name", "PureUnaryNativeMath|PureBinaryNativeMath"), ["dump_spec"], "extra_label", + function(dump_spec) {return callLeafInfo(dump_spec[0], 1);}); editProperty(matches("name", "CallLeafDirect|CallLeafDirectVector|CallLeafNoFPDirect"), ["dump_spec"], "extra_label", function(dump_spec) {return callLeafInfo(dump_spec[0], 0);}); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 0b22452356185..b1e16f2a07cdb 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2717,13 +2717,13 @@ public class IRNode { public static final String MOD_F = PREFIX + "MOD_F" + POSTFIX; static { - String regex = START + "ModF" + MID + END; + String regex = START + "PureModF" + MID + END; macroNodes(MOD_F, regex); } public static final String MOD_D = PREFIX + "MOD_D" + POSTFIX; static { - String regex = START + "ModD" + MID + END; + String regex = START + "PureModD" + MID + END; macroNodes(MOD_D, regex); }