--- old/src/hotspot/share/opto/callnode.cpp 2018-11-15 11:25:55.135781509 +0100 +++ new/src/hotspot/share/opto/callnode.cpp 2018-11-15 11:25:46.493765101 +0100 @@ -1076,10 +1076,19 @@ //============================================================================= +uint CallLeafNode::size_of() const { return sizeof(*this); } +uint CallLeafNode::cmp(const Node &n) const { + CallLeafNode &call = (CallLeafNode&)n; + return CallRuntimeNode::cmp(call) && _preserves_fp_registers == call._preserves_fp_registers; +} + #ifndef PRODUCT void CallLeafNode::dump_spec(outputStream *st) const { st->print("# "); st->print("%s", _name); + if (_preserves_fp_registers) { + st->print("preserves_fp_registers"); + } CallNode::dump_spec(st); } #endif --- old/src/hotspot/share/opto/callnode.hpp 2018-11-15 11:26:03.919798186 +0100 +++ new/src/hotspot/share/opto/callnode.hpp 2018-11-15 11:25:55.239781706 +0100 @@ -763,7 +763,9 @@ //------------------------------CallRuntimeNode-------------------------------- // Make a direct subroutine call node into compiled C++ code. class CallRuntimeNode : public CallNode { +protected: virtual uint cmp( const Node &n ) const; +private: virtual uint size_of() const; // Size is bigger public: CallRuntimeNode(const TypeFunc* tf, address addr, const char* name, @@ -786,15 +788,23 @@ // Make a direct subroutine call node into compiled C++ code, without // safepoints class CallLeafNode : public CallRuntimeNode { +private: + bool _preserves_fp_registers; +protected: + virtual uint cmp(const Node &n) const; + virtual uint size_of() const; // Size is bigger + public: CallLeafNode(const TypeFunc* tf, address addr, const char* name, - const TypePtr* adr_type) - : CallRuntimeNode(tf, addr, name, adr_type) + const TypePtr* adr_type, bool preserves_fp_registers = false) + : CallRuntimeNode(tf, addr, name, adr_type), + _preserves_fp_registers(preserves_fp_registers) { init_class_id(Class_CallLeaf); } virtual int Opcode() const; virtual bool guaranteed_safepoint() { return false; } + bool preserves_fp_registers() const { return _preserves_fp_registers; } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif --- old/src/hotspot/share/opto/lcm.cpp 2018-11-15 11:26:12.596814660 +0100 +++ new/src/hotspot/share/opto/lcm.cpp 2018-11-15 11:26:04.016798370 +0100 @@ -785,9 +785,12 @@ //------------------------------add_call_kills------------------------------------- // helper function that adds caller save registers to MachProjNode -static void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) { +static void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe, bool exclude_fp) { // Fill in the kill mask for the call for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) { + if (exclude_fp && (register_save_type[r] == Op_RegF || register_save_type[r] == Op_RegD)) { + continue; + } if( !regs.Member(r) ) { // Not already defined by the call // Save-on-call register? if ((save_policy[r] == 'C') || @@ -888,7 +891,7 @@ proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask()); } - add_call_kills(proj, regs, save_policy, exclude_soe); + add_call_kills(proj, regs, save_policy, exclude_soe, mcall->preserves_fp_registers()); return node_cnt; } @@ -1129,7 +1132,7 @@ map_node_to_block(proj, block); block->insert_node(proj, phi_cnt++); - add_call_kills(proj, regs, _matcher._c_reg_save_policy, false); + add_call_kills(proj, regs, _matcher._c_reg_save_policy, false, false); } // Children are now all ready --- old/src/hotspot/share/opto/machnode.cpp 2018-11-15 11:26:21.567831692 +0100 +++ new/src/hotspot/share/opto/machnode.cpp 2018-11-15 11:26:12.695814848 +0100 @@ -801,6 +801,20 @@ MachCallNode::dump_spec(st); } #endif + +uint MachCallLeafNode::size_of() const { return sizeof(*this); } +uint MachCallLeafNode::cmp( const Node &n ) const { + MachCallLeafNode &call = (MachCallLeafNode&)n; + return MachCallRuntimeNode::cmp(call) && _preserves_fp_registers == call._preserves_fp_registers; +} +#ifndef PRODUCT +void MachCallLeafNode::dump_spec(outputStream *st) const { + if (_preserves_fp_registers) { + st->print("preserves_fp_registers "); + } + MachCallRuntimeNode::dump_spec(st); +} +#endif //============================================================================= // A shared JVMState for all HaltNodes. Indicates the start of debug info // is at TypeFunc::Parms. Only required for SOE register spill handling - --- old/src/hotspot/share/opto/machnode.hpp 2018-11-15 11:26:30.561848768 +0100 +++ new/src/hotspot/share/opto/machnode.hpp 2018-11-15 11:26:21.665831878 +0100 @@ -895,6 +895,8 @@ // Similar to cousin class CallNode::returns_pointer bool returns_pointer() const; + virtual bool preserves_fp_registers() const { return false; } + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -973,7 +975,9 @@ //------------------------------MachCallRuntimeNode---------------------------- // Machine-specific versions of subroutine calls class MachCallRuntimeNode : public MachCallNode { +protected: virtual uint cmp( const Node &n ) const; +private: virtual uint size_of() const; // Size is bigger public: const char *_name; // Printable name, if _method is NULL @@ -987,10 +991,20 @@ }; class MachCallLeafNode: public MachCallRuntimeNode { + virtual uint cmp( const Node &n ) const; + virtual uint size_of() const; // Size is bigger +private: + bool _preserves_fp_registers; public: MachCallLeafNode() : MachCallRuntimeNode() { init_class_id(Class_MachCallLeaf); } + + void set_preserves_fp_registers(bool v) { _preserves_fp_registers = v; } + virtual bool preserves_fp_registers() const { return _preserves_fp_registers; } +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; +#endif }; //------------------------------MachHaltNode----------------------------------- --- old/src/hotspot/share/opto/matcher.cpp 2018-11-15 11:26:39.576865884 +0100 +++ new/src/hotspot/share/opto/matcher.cpp 2018-11-15 11:26:30.658848952 +0100 @@ -1151,7 +1151,7 @@ const TypeTuple *domain; ciMethod* method = NULL; bool is_method_handle_invoke = false; // for special kill effects - if( sfpt->is_Call() ) { + if (sfpt->is_Call()) { call = sfpt->as_Call(); domain = call->tf()->domain(); cnt = domain->cnt(); @@ -1159,7 +1159,7 @@ // Match just the call, nothing else MachNode *m = match_tree(call); if (C->failing()) return NULL; - if( m == NULL ) { Matcher::soft_match_failure(); return NULL; } + if (m == NULL) { Matcher::soft_match_failure(); return NULL; } // Copy data from the Ideal SafePoint to the machine version mcall = m->as_MachCall(); @@ -1168,7 +1168,7 @@ mcall->set_entry_point(call->entry_point()); mcall->set_cnt( call->cnt()); - if( mcall->is_MachCallJava() ) { + if (mcall->is_MachCallJava()) { MachCallJavaNode *mcall_java = mcall->as_MachCallJava(); const CallJavaNode *call_java = call->as_CallJava(); method = call_java->method(); @@ -1181,15 +1181,21 @@ if (is_method_handle_invoke) { C->set_has_method_handle_invokes(true); } - if( mcall_java->is_MachCallStaticJava() ) + if (mcall_java->is_MachCallStaticJava()) { mcall_java->as_MachCallStaticJava()->_name = call_java->as_CallStaticJava()->_name; - if( mcall_java->is_MachCallDynamicJava() ) + } + if (mcall_java->is_MachCallDynamicJava()) { mcall_java->as_MachCallDynamicJava()->_vtable_index = call_java->as_CallDynamicJava()->_vtable_index; + } } - else if( mcall->is_MachCallRuntime() ) { + else if (mcall->is_MachCallRuntime()) { mcall->as_MachCallRuntime()->_name = call->as_CallRuntime()->_name; + if (mcall->is_MachCallLeaf()) { + bool preserves_fp_registers = call->as_CallLeaf()->preserves_fp_registers(); + mcall->as_MachCallLeaf()->set_preserves_fp_registers(preserves_fp_registers); + } } msfpt = mcall; }