# HG changeset patch # User goetz # Date 1387543874 -3600 # Node ID ad3b94907eed88af632fe0eae8313a94a6fbda13 # Parent 5da8bb64b3707862b0369d3d95f0391a63d837fc 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 diff -r 5da8bb64b370 -r ad3b94907eed src/cpu/ppc/vm/ppc.ad --- a/src/cpu/ppc/vm/ppc.ad Mon Dec 23 10:26:08 2013 -0800 +++ b/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) { + // 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 { call->add_req(in(i)); - } else { - // The expanded node does not need toc any more. - call->add_req(C->top()); } } // ...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); diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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 ) { diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/adlc/archDesc.hpp --- a/src/share/vm/adlc/archDesc.hpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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 diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/adlc/main.cpp --- a/src/share/vm/adlc/main.cpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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 diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/adlc/output_c.cpp --- a/src/share/vm/adlc/output_c.cpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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"); diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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 diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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; } diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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); diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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; } diff -r 5da8bb64b370 -r ad3b94907eed src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Mon Dec 23 10:26:08 2013 -0800 +++ b/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;