From 0574d537d0a3d5cbbf140d3f862f2ed629a8bf6c Mon Sep 17 00:00:00 2001 From: roland Date: Wed, 14 Sep 2011 09:22:51 +0200 Subject: [PATCH] 7077312: Provide a CALL effect for instruct declaration in the ad file Summary: abstracted way to declare that the MachNode has the effect of a call (kills caller save registers, preserves callee save registers) Reviewed-by: twisti, never --- src/share/vm/adlc/adlparse.cpp | 45 +++++++++++++----------- src/share/vm/adlc/adlparse.hpp | 2 +- src/share/vm/adlc/archDesc.cpp | 3 ++ src/share/vm/adlc/formssel.cpp | 7 ++-- src/share/vm/adlc/formssel.hpp | 5 ++- src/share/vm/adlc/output_h.cpp | 10 ++++++ src/share/vm/opto/block.hpp | 2 ++ src/share/vm/opto/idealGraphPrinter.cpp | 3 ++ src/share/vm/opto/lcm.cpp | 46 +++++++++++++++++++------ src/share/vm/opto/machnode.hpp | 3 ++ src/share/vm/opto/node.hpp | 3 +- 11 files changed, 93 insertions(+), 36 deletions(-) diff --git a/src/share/vm/adlc/adlparse.cpp b/src/share/vm/adlc/adlparse.cpp index e9b884752..5d9e5fd9f 100644 --- a/src/share/vm/adlc/adlparse.cpp +++ b/src/share/vm/adlc/adlparse.cpp @@ -3818,7 +3818,7 @@ void ADLParser::effect_parse(InstructForm *instr) { return; } // Get list of effect-operand pairs and insert into dictionary - else get_effectlist(instr->_effects, instr->_localNames); + else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call); // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc); @@ -4596,7 +4596,7 @@ void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) { // effect, and the second must be the name of an operand defined in the // operand list of this instruction. Stores the names with a pointer to the // effect form in a local effects table. -void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) { +void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) { OperandForm *opForm; Effect *eForm; char *ident; @@ -4629,26 +4629,31 @@ void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) { // Debugging Stuff if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident); skipws(); - // Get name of operand and check that it is in the local name table - if( (ident = get_unique_ident(effects, "effect")) == NULL) { - parse_err(SYNERR, "missing operand identifier in effect list\n"); - return; - } - const Form *form = operands[ident]; - opForm = form ? form->is_operand() : NULL; - if( opForm == NULL ) { - if( form && form->is_opclass() ) { - const char* cname = form->is_opclass()->_ident; - parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident); - } else { - parse_err(SYNERR, "undefined operand %s in effect list\n", ident); + if (eForm->is(Component::CALL)) { + if (_AD._adl_debug > 1) fprintf(stderr, "\n"); + has_call = true; + } else { + // Get name of operand and check that it is in the local name table + if( (ident = get_unique_ident(effects, "effect")) == NULL) { + parse_err(SYNERR, "missing operand identifier in effect list\n"); + return; } - return; + const Form *form = operands[ident]; + opForm = form ? form->is_operand() : NULL; + if( opForm == NULL ) { + if( form && form->is_opclass() ) { + const char* cname = form->is_opclass()->_ident; + parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident); + } else { + parse_err(SYNERR, "undefined operand %s in effect list\n", ident); + } + return; + } + // Add the pair to the effects table + effects.Insert(ident, eForm); + // Debugging Stuff + if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident); } - // Add the pair to the effects table - effects.Insert(ident, eForm); - // Debugging Stuff - if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident); skipws(); } while(_curchar == ','); diff --git a/src/share/vm/adlc/adlparse.hpp b/src/share/vm/adlc/adlparse.hpp index ee33b88ef..8d87ab968 100644 --- a/src/share/vm/adlc/adlparse.hpp +++ b/src/share/vm/adlc/adlparse.hpp @@ -232,7 +232,7 @@ protected: char *get_relation_dup(void); void get_oplist(NameList ¶meters, FormDict &operands);// Parse type-operand pairs - void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs + void get_effectlist(FormDict &effects, FormDict &operands, bool& has_call); // Parse effect-operand pairs // Return the contents of a parenthesized expression. // Requires initial '(' and consumes final ')', which is replaced by '\0'. char *get_paren_expr(const char *description, bool include_location = false); diff --git a/src/share/vm/adlc/archDesc.cpp b/src/share/vm/adlc/archDesc.cpp index 5b4c1faad..940bb3131 100644 --- a/src/share/vm/adlc/archDesc.cpp +++ b/src/share/vm/adlc/archDesc.cpp @@ -1018,6 +1018,9 @@ void ArchDesc::initBaseOpTypes() { ident = "TEMP"; eForm = new Effect(ident); _globalNames.Insert(ident, eForm); + ident = "CALL"; + eForm = new Effect(ident); + _globalNames.Insert(ident, eForm); } // diff --git a/src/share/vm/adlc/formssel.cpp b/src/share/vm/adlc/formssel.cpp index d3817ed4a..c1d39849b 100644 --- a/src/share/vm/adlc/formssel.cpp +++ b/src/share/vm/adlc/formssel.cpp @@ -31,7 +31,8 @@ InstructForm::InstructForm(const char *id, bool ideal_only) : _ident(id), _ideal_only(ideal_only), _localNames(cmpstr, hashstr, Form::arena), _effects(cmpstr, hashstr, Form::arena), - _is_mach_constant(false) + _is_mach_constant(false), + _has_call(false) { _ftype = Form::INS; @@ -62,7 +63,8 @@ InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule) : _ident(id), _ideal_only(false), _localNames(instr->_localNames), _effects(instr->_effects), - _is_mach_constant(false) + _is_mach_constant(false), + _has_call(false) { _ftype = Form::INS; @@ -1754,6 +1756,7 @@ static int effect_lookup(const char *name) { if(!strcmp(name, "USE_KILL")) return Component::USE_KILL; if(!strcmp(name, "TEMP")) return Component::TEMP; if(!strcmp(name, "INVALID")) return Component::INVALID; + if(!strcmp(name, "CALL")) return Component::CALL; assert( false,"Invalid effect name specified\n"); return Component::INVALID; } diff --git a/src/share/vm/adlc/formssel.hpp b/src/share/vm/adlc/formssel.hpp index 50d7a7063..b2d3ec74d 100644 --- a/src/share/vm/adlc/formssel.hpp +++ b/src/share/vm/adlc/formssel.hpp @@ -111,6 +111,8 @@ public: ComponentList _components; // List of Components matches MachNode's // operand structure + bool _has_call; // contain a call and caller save registers should be saved? + // Public Methods InstructForm(const char *id, bool ideal_only = false); InstructForm(const char *id, InstructForm *instr, MatchRule *rule); @@ -895,7 +897,8 @@ public: DEF = 0x2, USE_DEF = 0x3, KILL = 0x4, USE_KILL = 0x5, SYNTHETIC = 0x8, - TEMP = USE | SYNTHETIC + TEMP = USE | SYNTHETIC, + CALL = 0x10 }; }; diff --git a/src/share/vm/adlc/output_h.cpp b/src/share/vm/adlc/output_h.cpp index 9e609b8dc..ea066eb0d 100644 --- a/src/share/vm/adlc/output_h.cpp +++ b/src/share/vm/adlc/output_h.cpp @@ -1720,6 +1720,16 @@ void ArchDesc::declareClasses(FILE *fp) { } } + // flag: if this instruction is implemented with a call + if ( instr->_has_call ) { + if ( node_flags_set ) { + fprintf(fp," | Flag_has_call"); + } else { + fprintf(fp,"init_flags(Flag_has_call"); + node_flags_set = true; + } + } + if ( node_flags_set ) { fprintf(fp,"); "); } diff --git a/src/share/vm/opto/block.hpp b/src/share/vm/opto/block.hpp index 51869c8da..ef5c8d6e4 100644 --- a/src/share/vm/opto/block.hpp +++ b/src/share/vm/opto/block.hpp @@ -281,6 +281,8 @@ class Block : public CFGElement { // Find and remove n from block list void find_remove( const Node *n ); + // helper function that adds caller save registers to MachProjNode + void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe); // Schedule a call next in the block uint sched_call(Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call); diff --git a/src/share/vm/opto/idealGraphPrinter.cpp b/src/share/vm/opto/idealGraphPrinter.cpp index a5a0c6588..f9f40a37d 100644 --- a/src/share/vm/opto/idealGraphPrinter.cpp +++ b/src/share/vm/opto/idealGraphPrinter.cpp @@ -447,6 +447,9 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { if (flags & Node::Flag_may_be_short_branch) { print_prop("may_be_short_branch", "true"); } + if (flags & Node::Flag_has_call) { + print_prop("has_call", "true"); + } if (C->matcher() != NULL) { if (C->matcher()->is_shared(node)) { diff --git a/src/share/vm/opto/lcm.cpp b/src/share/vm/opto/lcm.cpp index 425e10bad..287b6ed05 100644 --- a/src/share/vm/opto/lcm.cpp +++ b/src/share/vm/opto/lcm.cpp @@ -548,6 +548,22 @@ void Block::needed_for_next_call(Node *this_call, VectorSet &next_call, Block_Ar set_next_call(call, next_call, bbs); } +//------------------------------add_call_kills------------------------------------- +void Block::add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) { + // 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( !regs.Member(r) ) { // Not already defined by the call + // Save-on-call register? + if ((save_policy[r] == 'C') || + (save_policy[r] == 'A') || + ((save_policy[r] == 'E') && exclude_soe)) { + proj->_rout.Insert(r); + } + } + } +} + + //------------------------------sched_call------------------------------------- uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call ) { RegMask regs; @@ -631,17 +647,7 @@ uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_ proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask()); } - // 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( !regs.Member(r) ) { // Not already defined by the call - // Save-on-call register? - if ((save_policy[r] == 'C') || - (save_policy[r] == 'A') || - ((save_policy[r] == 'E') && exclude_soe)) { - proj->_rout.Insert(r); - } - } - } + add_call_kills(proj, regs, save_policy, exclude_soe); return node_cnt; } @@ -776,6 +782,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect } #endif + uint max_idx = matcher.C->unique(); // Pull from worklist and schedule while( worklist.size() ) { // Worklist is not ready @@ -815,11 +822,28 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect phi_cnt = sched_call(matcher, cfg->_bbs, phi_cnt, worklist, ready_cnt, mcall, next_call); continue; } + + if (n->is_Mach() && n->as_Mach()->has_call()) { + RegMask regs; + regs.Insert(matcher.c_frame_pointer()); + regs.OR(n->out_RegMask()); + + MachProjNode *proj = new (matcher.C, 1) MachProjNode( n, 1, RegMask::Empty, MachProjNode::fat_proj ); + cfg->_bbs.map(proj->_idx,this); + _nodes.insert(phi_cnt++, proj); + + add_call_kills(proj, regs, matcher._c_reg_save_policy, false); + } + // Children are now all ready for (DUIterator_Fast i5max, i5 = n->fast_outs(i5max); i5 < i5max; i5++) { Node* m = n->fast_out(i5); // Get user if( cfg->_bbs[m->_idx] != this ) continue; if( m->is_Phi() ) continue; + if (m->_idx > max_idx) { // new node, skip it + assert(m->is_MachProj() && n->is_Mach() && n->as_Mach()->has_call(), "unexpected node types"); + continue; + } if( !--ready_cnt[m->_idx] ) worklist.push(m); } diff --git a/src/share/vm/opto/machnode.hpp b/src/share/vm/opto/machnode.hpp index c44c8d0d8..566e031d1 100644 --- a/src/share/vm/opto/machnode.hpp +++ b/src/share/vm/opto/machnode.hpp @@ -190,6 +190,9 @@ public: // Avoid back to back some instructions on some CPUs. bool avoid_back_to_back() const { return (flags() & Flag_avoid_back_to_back) != 0; } + // instruction implemented with a call + bool has_call() const { return (flags() & Flag_has_call) != 0; } + // First index in _in[] corresponding to operand, or -1 if there is none int operand_index(uint operand) const; diff --git a/src/share/vm/opto/node.hpp b/src/share/vm/opto/node.hpp index 8564a7775..e10cad472 100644 --- a/src/share/vm/opto/node.hpp +++ b/src/share/vm/opto/node.hpp @@ -641,7 +641,8 @@ public: Flag_is_dead_loop_safe = Flag_is_cisc_alternate << 1, Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1, Flag_avoid_back_to_back = Flag_may_be_short_branch << 1, - _max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination + Flag_has_call = Flag_avoid_back_to_back << 1, + _max_flags = (Flag_has_call << 1) - 1 // allow flags combination }; private: -- GitLab