8030863: PPC64: (part 220): ConstantTableBase for calls between args and jvms
Summary: Add ConstantTableBase node edge after parameters and before jvms. Adapt jvms offsets.
Reviewed-by: kvn
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Fri Dec 20 13:51:14 2013 +0100
@@ -3563,9 +3563,6 @@
// postalloc expand emitter for virtual calls.
enc_class postalloc_expand_java_dynamic_call_sched(method meth, iRegLdst toc) %{
- // Toc is in return address field, though not accessible via postalloc_expand
- // functionaliy.
- Node *toc = in(TypeFunc::ReturnAdr);
// Create the nodes for loading the IC from the TOC.
loadConLNodesTuple loadConLNodes_IC =
@@ -3592,23 +3589,21 @@
// New call needs all inputs of old call.
// Req...
for (uint i = 0; i < req(); ++i) {
- if (i != TypeFunc::ReturnAdr) {
- call->add_req(in(i));
+ // The expanded node does not need toc any more.
+ // Add the inline cache constant here instead. This expresses the
+ // register of the inline cache must be live at the call.
+ // Else we would have to adapt JVMState by -1.
+ if (i == mach_constant_base_node_input()) {
+ call->add_req(loadConLNodes_IC._last);
} else {
- // The expanded node does not need toc any more.
- call->add_req(C->top());
+ call->add_req(in(i));
}
}
// ...as well as prec
- for (uint i = req(); i < len() ; ++i) {
+ for (uint i = req(); i < len(); ++i) {
call->add_prec(in(i));
}
- // The cache must come before the call, but it's not a req edge.
- // GL: actually it should be a req edge to express that the
- // register must be live in the Call. But as R19 is declared to be
- // the inline_cache_reg that's fine.
- call->add_prec(loadConLNodes_IC._last);
// Remember nodes loading the inline cache into r19.
call->_load_ic_hi_node = loadConLNodes_IC._large_hi;
call->_load_ic_node = loadConLNodes_IC._small;
@@ -3638,13 +3633,13 @@
// Must be invalid_vtable_index, not nonvirtual_vtable_index.
assert(_vtable_index == Method::invalid_vtable_index, "correct sentinel value");
Register ic_reg = as_Register(Matcher::inline_cache_reg_encode());
- AddressLiteral oop = __ allocate_metadata_address((Metadata *)Universe::non_oop_word());
-
- address virtual_call_oop_addr = __ pc();
- __ load_const_from_method_toc(ic_reg, oop, Rtoc);
+ AddressLiteral meta = __ allocate_metadata_address((Metadata *)Universe::non_oop_word());
+
+ address virtual_call_meta_addr = __ pc();
+ __ load_const_from_method_toc(ic_reg, meta, Rtoc);
// CALL to fixup routine. Fixup routine uses ScopeDesc info
// to determine who we intended to call.
- __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr));
+ __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr));
emit_call_with_trampoline_stub(_masm, (address)$meth$$method, relocInfo::none);
assert(((MachCallDynamicJavaNode*)this)->ret_addr_offset() == __ offset() - start_offset,
"Fix constant in ret_addr_offset()");
@@ -3674,6 +3669,7 @@
"Fix constant in ret_addr_offset()");
}
#endif
+ guarantee(0, "Fix handling of toc edge: messes up derived/base pairs.");
Unimplemented(); // ret_addr_offset not yet fixed. Depends on compressed oops (load klass!).
%}
@@ -3775,16 +3771,14 @@
// New call needs all inputs of old call.
// Req...
for (uint i = 0; i < req(); ++i) {
- if (i != TypeFunc::ReturnAdr) {
+ if (i != mach_constant_base_node_input()) {
call->add_req(in(i));
- } else {
- // put the mtctr where ReturnAdr would be
- call->add_req(mtctr);
}
}
// These must be reqired edges, as the registers are live up to
// the call. Else the constants are handled as kills.
+ call->add_req(mtctr);
call->add_req(loadConLNodes_Env._last);
call->add_req(loadConLNodes_Toc._last);
@@ -3818,7 +3812,7 @@
// These two registers define part of the calling convention between
// compiled code and the interpreter.
- // Inline Cache Register or methodOop for I2C.
+ // Inline Cache Register or method for I2C.
inline_cache_reg(R19); // R19_method
// Method Oop Register when calling interpreter.
@@ -6149,8 +6143,8 @@
size(4);
ins_encode %{
// TODO: PPC port $archOpcode(ppc64Opcode_ld);
- int offset = ra_->C->in_scratch_emit_size() ? 0 : MacroAssembler::largeoffset_si16_si16_lo(_const_toc_offset_hi_node->_const_toc_offset);
- __ ld($dst$$Register, offset, $base$$Register);
+ int offset = ra_->C->in_scratch_emit_size() ? 0 : _const_toc_offset_hi_node->_const_toc_offset;
+ __ ld($dst$$Register, MacroAssembler::largeoffset_si16_si16_lo(offset), $base$$Register);
%}
ins_pipe(pipe_class_memory);
%}
@@ -6784,7 +6778,7 @@
Label done;
__ beq($crx$$CondRegister, done);
__ add($dst$$Register, $src1$$Register, R30);
- // TODO PPC port __ endgroup_if_needed(_size == 12);
+ // TODO PPC port __ endgroup_if_needed(_size == 12);
__ bind(done);
%}
ins_pipe(pipe_class_default);
--- a/hotspot/src/share/vm/adlc/archDesc.cpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/adlc/archDesc.cpp Fri Dec 20 13:51:14 2013 +0100
@@ -172,7 +172,8 @@
_internalOps(cmpstr,hashstr, Form::arena),
_internalMatch(cmpstr,hashstr, Form::arena),
_chainRules(cmpstr,hashstr, Form::arena),
- _cisc_spill_operand(NULL) {
+ _cisc_spill_operand(NULL),
+ _needs_clone_jvms(false) {
// Initialize the opcode to MatchList table with NULLs
for( int i=0; i<_last_opcode; ++i ) {
--- a/hotspot/src/share/vm/adlc/archDesc.hpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/adlc/archDesc.hpp Fri Dec 20 13:51:14 2013 +0100
@@ -121,6 +121,12 @@
// to access [stack_pointer + offset]
OperandForm *_cisc_spill_operand;
+ // If a Call node uses $constanttablebase, it gets MachConstantBaseNode
+ // by the matcher and the matcher will modify the jvms. If so, jvm states
+ // always have to be cloned when a node is cloned. Adlc generates
+ // Compile::needs_clone_jvms() accordingly.
+ bool _needs_clone_jvms;
+
// Methods for outputting the DFA
void gen_match(FILE *fp, MatchList &mlist, ProductionState &status, Dict &operands_chained_from);
void chain_rule(FILE *fp, const char *indent, const char *ideal,
@@ -289,6 +295,7 @@
void addPreHeaderBlocks(FILE *fp_hpp);
void addHeaderBlocks(FILE *fp_hpp);
void addSourceBlocks(FILE *fp_cpp);
+ void generate_needs_clone_jvms(FILE *fp_cpp);
void generate_adlc_verification(FILE *fp_cpp);
// output declaration of class State
--- a/hotspot/src/share/vm/adlc/main.cpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/adlc/main.cpp Fri Dec 20 13:51:14 2013 +0100
@@ -306,6 +306,7 @@
AD.buildInstructMatchCheck(AD._CPP_file._fp); // .cpp
// define methods for machine dependent frame management
AD.buildFrameMethods(AD._CPP_file._fp); // .cpp
+ AD.generate_needs_clone_jvms(AD._CPP_file._fp);
// do this last:
AD.addPreprocessorChecks(AD._CPP_file._fp); // .cpp
--- a/hotspot/src/share/vm/adlc/output_c.cpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/adlc/output_c.cpp Fri Dec 20 13:51:14 2013 +0100
@@ -1842,17 +1842,23 @@
// There are nodes that don't use $constantablebase, but still require that it
// is an input to the node. Example: divF_reg_immN, Repl32B_imm on x86_64.
if (node->is_mach_constant() || node->needs_constant_base()) {
- fprintf(fp," add_req(C->mach_constant_base_node());\n");
+ if (node->is_ideal_call() != Form::invalid_type &&
+ node->is_ideal_call() != Form::JAVA_LEAF) {
+ fprintf(fp, " // MachConstantBaseNode added in matcher.\n");
+ _needs_clone_jvms = true;
+ } else {
+ fprintf(fp, " add_req(C->mach_constant_base_node());\n");
+ }
}
- fprintf(fp,"\n");
- if( node->expands() ) {
- fprintf(fp," return result;\n");
+ fprintf(fp, "\n");
+ if (node->expands()) {
+ fprintf(fp, " return result;\n");
} else {
- fprintf(fp," return this;\n");
+ fprintf(fp, " return this;\n");
}
- fprintf(fp,"}\n");
- fprintf(fp,"\n");
+ fprintf(fp, "}\n");
+ fprintf(fp, "\n");
}
@@ -3642,6 +3648,11 @@
return callconv;
}
+void ArchDesc::generate_needs_clone_jvms(FILE *fp_cpp) {
+ fprintf(fp_cpp, "bool Compile::needs_clone_jvms() { return %s; }\n\n",
+ _needs_clone_jvms ? "true" : "false");
+}
+
//---------------------------generate_assertion_checks-------------------
void ArchDesc::generate_adlc_verification(FILE *fp_cpp) {
fprintf(fp_cpp, "\n");
--- a/hotspot/src/share/vm/adlc/output_h.cpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/adlc/output_h.cpp Fri Dec 20 13:51:14 2013 +0100
@@ -1665,7 +1665,15 @@
if (instr->needs_constant_base() &&
!instr->is_mach_constant()) { // These inherit the funcion from MachConstantNode.
- fprintf(fp," virtual uint mach_constant_base_node_input() const { return req()-1; }\n");
+ fprintf(fp," virtual uint mach_constant_base_node_input() const { ");
+ if (instr->is_ideal_call() != Form::invalid_type &&
+ instr->is_ideal_call() != Form::JAVA_LEAF) {
+ // MachConstantBase goes behind arguments, but before jvms.
+ fprintf(fp,"assert(tf() && tf()->domain(), \"\"); return tf()->domain()->cnt();");
+ } else {
+ fprintf(fp,"return req()-1;");
+ }
+ fprintf(fp," }\n");
}
// Allow machine-independent optimization, invert the sense of the IF test
--- a/hotspot/src/share/vm/opto/callnode.cpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/opto/callnode.cpp Fri Dec 20 13:51:14 2013 +0100
@@ -595,6 +595,18 @@
}
}
+// Adapt offsets in in-array after adding or removing an edge.
+// Prerequisite is that the JVMState is used by only one node.
+void JVMState::adapt_position(int delta) {
+ for (JVMState* jvms = this; jvms != NULL; jvms = jvms->caller()) {
+ jvms->set_locoff(jvms->locoff() + delta);
+ jvms->set_stkoff(jvms->stkoff() + delta);
+ jvms->set_monoff(jvms->monoff() + delta);
+ jvms->set_scloff(jvms->scloff() + delta);
+ jvms->set_endoff(jvms->endoff() + delta);
+ }
+}
+
//=============================================================================
uint CallNode::cmp( const Node &n ) const
{ return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; }
--- a/hotspot/src/share/vm/opto/callnode.hpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/opto/callnode.hpp Fri Dec 20 13:51:14 2013 +0100
@@ -299,6 +299,7 @@
JVMState* clone_deep(Compile* C) const; // recursively clones caller chain
JVMState* clone_shallow(Compile* C) const; // retains uncloned caller
void set_map_deep(SafePointNode *map);// reset map for all callers
+ void adapt_position(int delta); // Adapt offsets in in-array after adding an edge.
#ifndef PRODUCT
void format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const;
@@ -559,9 +560,15 @@
// Are we guaranteed that this node is a safepoint? Not true for leaf calls and
// for some macro nodes whose expansion does not have a safepoint on the fast path.
virtual bool guaranteed_safepoint() { return true; }
- // For macro nodes, the JVMState gets modified during expansion, so when cloning
- // the node the JVMState must be cloned.
- virtual void clone_jvms(Compile* C) { } // default is not to clone
+ // For macro nodes, the JVMState gets modified during expansion. If calls
+ // use MachConstantBase, it gets modified during matching. So when cloning
+ // the node the JVMState must be cloned. Default is not to clone.
+ virtual void clone_jvms(Compile* C) {
+ if (C->needs_clone_jvms() && jvms() != NULL) {
+ set_jvms(jvms()->clone_deep(C));
+ jvms()->set_map_deep(this);
+ }
+ }
// Returns true if the call may modify n
virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase);
--- a/hotspot/src/share/vm/opto/compile.hpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/opto/compile.hpp Fri Dec 20 13:51:14 2013 +0100
@@ -758,6 +758,8 @@
MachConstantBaseNode* mach_constant_base_node();
bool has_mach_constant_base_node() const { return _mach_constant_base_node != NULL; }
+ // Generated by adlc, true if CallNode requires MachConstantBase.
+ bool needs_clone_jvms();
// Handy undefined Node
Node* top() const { return _top; }
--- a/hotspot/src/share/vm/opto/matcher.cpp Wed Jan 08 11:24:00 2014 -0800
+++ b/hotspot/src/share/vm/opto/matcher.cpp Fri Dec 20 13:51:14 2013 +0100
@@ -1338,12 +1338,24 @@
}
// Debug inputs begin just after the last incoming parameter
- assert( (mcall == NULL) || (mcall->jvms() == NULL) ||
- (mcall->jvms()->debug_start() + mcall->_jvmadj == mcall->tf()->domain()->cnt()), "" );
+ assert((mcall == NULL) || (mcall->jvms() == NULL) ||
+ (mcall->jvms()->debug_start() + mcall->_jvmadj == mcall->tf()->domain()->cnt()), "");
// Move the OopMap
msfpt->_oop_map = sfpt->_oop_map;
+ // Add additional edges.
+ if (msfpt->mach_constant_base_node_input() != (uint)-1 && !msfpt->is_MachCallLeaf()) {
+ // For these calls we can not add MachConstantBase in expand(), as the
+ // ins are not complete then.
+ msfpt->ins_req(msfpt->mach_constant_base_node_input(), C->mach_constant_base_node());
+ if (msfpt->jvms() &&
+ msfpt->mach_constant_base_node_input() <= msfpt->jvms()->debug_start() + msfpt->_jvmadj) {
+ // We added an edge before jvms, so we must adapt the position of the ins.
+ msfpt->jvms()->adapt_position(+1);
+ }
+ }
+
// Registers killed by the call are set in the local scheduling pass
// of Global Code Motion.
return msfpt;