Mercurial > hg > graal-compiler
view src/share/vm/adlc/formsopt.cpp @ 2149:7e37af9d69ef
7011379: G1: overly long concurrent marking cycles
Summary: This changeset introduces filtering of SATB buffers at the point when they are about to be enqueued. If this filtering clears enough entries on each buffer, the buffer can then be re-used and not enqueued. This cuts down the number of SATB buffers that need to be processed by the concurrent marking threads.
Reviewed-by: johnc, ysr
author | tonyp |
---|---|
date | Wed, 19 Jan 2011 09:35:17 -0500 |
parents | f95d63e2154a |
children | db2e64ca2d5a |
line wrap: on
line source
/* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ // FORMS.CPP - Definitions for ADL Parser Forms Classes #include "adlc.hpp" //==============================Register Allocation============================ int RegisterForm::_reg_ctr = 0; //------------------------------RegisterForm----------------------------------- // Constructor RegisterForm::RegisterForm() : _regDef(cmpstr,hashstr, Form::arena), _regClass(cmpstr,hashstr, Form::arena), _allocClass(cmpstr,hashstr, Form::arena) { } RegisterForm::~RegisterForm() { } // record a new register definition void RegisterForm::addRegDef(char *name, char *callingConv, char *c_conv, char *idealtype, char *encoding, char* concrete) { RegDef *regDef = new RegDef(name, callingConv, c_conv, idealtype, encoding, concrete); _rdefs.addName(name); _regDef.Insert(name,regDef); } // record a new register class RegClass *RegisterForm::addRegClass(const char *className) { RegClass *regClass = new RegClass(className); _rclasses.addName(className); _regClass.Insert(className,regClass); return regClass; } // record a new register class AllocClass *RegisterForm::addAllocClass(char *className) { AllocClass *allocClass = new AllocClass(className); _aclasses.addName(className); _allocClass.Insert(className,allocClass); return allocClass; } // Called after parsing the Register block. Record the register class // for spill-slots/regs. void RegisterForm::addSpillRegClass() { // Stack slots start at the next available even register number. _reg_ctr = (_reg_ctr+1) & ~1; const char *rc_name = "stack_slots"; RegClass *reg_class = new RegClass(rc_name); reg_class->_stack_or_reg = true; _rclasses.addName(rc_name); _regClass.Insert(rc_name,reg_class); } // Provide iteration over all register definitions // in the order used by the register allocator void RegisterForm::reset_RegDefs() { _current_ac = NULL; _aclasses.reset(); } RegDef *RegisterForm::iter_RegDefs() { // Check if we need to get the next AllocClass if ( _current_ac == NULL ) { const char *ac_name = _aclasses.iter(); if( ac_name == NULL ) return NULL; // No more allocation classes _current_ac = (AllocClass*)_allocClass[ac_name]; _current_ac->_regDefs.reset(); assert( _current_ac != NULL, "Name must match an allocation class"); } const char *rd_name = _current_ac->_regDefs.iter(); if( rd_name == NULL ) { // At end of this allocation class, check the next _current_ac = NULL; return iter_RegDefs(); } RegDef *reg_def = (RegDef*)_current_ac->_regDef[rd_name]; assert( reg_def != NULL, "Name must match a register definition"); return reg_def; } // return the register definition with name 'regName' RegDef *RegisterForm::getRegDef(const char *regName) { RegDef *regDef = (RegDef*)_regDef[regName]; return regDef; } // return the register class with name 'className' RegClass *RegisterForm::getRegClass(const char *className) { RegClass *regClass = (RegClass*)_regClass[className]; return regClass; } // Check that register classes are compatible with chunks bool RegisterForm::verify() { bool valid = true; // Verify Register Classes // check that each register class contains registers from one chunk const char *rc_name = NULL; _rclasses.reset(); while ( (rc_name = _rclasses.iter()) != NULL ) { // Check the chunk value for all registers in this class RegClass *reg_class = getRegClass(rc_name); assert( reg_class != NULL, "InternalError() no matching register class"); } // end of RegClasses // Verify that every register has been placed into an allocation class RegDef *reg_def = NULL; reset_RegDefs(); uint num_register_zero = 0; while ( (reg_def = iter_RegDefs()) != NULL ) { if( reg_def->register_num() == 0 ) ++num_register_zero; } if( num_register_zero > 1 ) { fprintf(stderr, "ERROR: More than one register has been assigned register-number 0.\n" "Probably because a register has not been entered into an allocation class.\n"); } return valid; } // Compute RegMask size int RegisterForm::RegMask_Size() { // Need at least this many words int words_for_regs = (_reg_ctr + 31)>>5; // Add a few for incoming & outgoing arguments to calls. // Round up to the next doubleword size. return (words_for_regs + 2 + 1) & ~1; } void RegisterForm::dump() { // Debug printer output(stderr); } void RegisterForm::output(FILE *fp) { // Write info to output files const char *name; fprintf(fp,"\n"); fprintf(fp,"-------------------- Dump RegisterForm --------------------\n"); for(_rdefs.reset(); (name = _rdefs.iter()) != NULL;) { ((RegDef*)_regDef[name])->output(fp); } fprintf(fp,"\n"); for (_rclasses.reset(); (name = _rclasses.iter()) != NULL;) { ((RegClass*)_regClass[name])->output(fp); } fprintf(fp,"\n"); for (_aclasses.reset(); (name = _aclasses.iter()) != NULL;) { ((AllocClass*)_allocClass[name])->output(fp); } fprintf(fp,"-------------------- end RegisterForm --------------------\n"); } //------------------------------RegDef----------------------------------------- // Constructor RegDef::RegDef(char *regname, char *callconv, char *c_conv, char * idealtype, char * encode, char * concrete) : _regname(regname), _callconv(callconv), _c_conv(c_conv), _idealtype(idealtype), _register_encode(encode), _concrete(concrete), _register_num(0) { // Chunk and register mask are determined by the register number // _register_num is set when registers are added to an allocation class } RegDef::~RegDef() { // Destructor } void RegDef::set_register_num(uint32 register_num) { _register_num = register_num; } // Bit pattern used for generating machine code const char* RegDef::register_encode() const { return _register_encode; } // Register number used in machine-independent code uint32 RegDef::register_num() const { return _register_num; } void RegDef::dump() { output(stderr); } void RegDef::output(FILE *fp) { // Write info to output files fprintf(fp,"RegDef: %s (%s) encode as %s using number %d\n", _regname, (_callconv?_callconv:""), _register_encode, _register_num); fprintf(fp,"\n"); } //------------------------------RegClass--------------------------------------- // Construct a register class into which registers will be inserted RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { } // record a register in this class void RegClass::addReg(RegDef *regDef) { _regDefs.addName(regDef->_regname); _regDef.Insert((void*)regDef->_regname, regDef); } // Number of registers in class uint RegClass::size() const { return _regDef.Size(); } const RegDef *RegClass::get_RegDef(const char *rd_name) const { return (const RegDef*)_regDef[rd_name]; } void RegClass::reset() { _regDefs.reset(); } const char *RegClass::rd_name_iter() { return _regDefs.iter(); } RegDef *RegClass::RegDef_iter() { const char *rd_name = rd_name_iter(); RegDef *reg_def = rd_name ? (RegDef*)_regDef[rd_name] : NULL; return reg_def; } const RegDef* RegClass::find_first_elem() { const RegDef* first = NULL; const RegDef* def = NULL; reset(); while ((def = RegDef_iter()) != NULL) { if (first == NULL || def->register_num() < first->register_num()) { first = def; } } assert(first != NULL, "empty mask?"); return first;; } // Collect all the registers in this register-word. One bit per register. int RegClass::regs_in_word( int wordnum, bool stack_also ) { int word = 0; const char *name; for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) { int rnum = ((RegDef*)_regDef[name])->register_num(); if( (rnum >> 5) == wordnum ) word |= (1 << (rnum & 31)); } if( stack_also ) { // Now also collect stack bits for( int i = 0; i < 32; i++ ) if( wordnum*32+i >= RegisterForm::_reg_ctr ) word |= (1 << i); } return word; } void RegClass::dump() { output(stderr); } void RegClass::output(FILE *fp) { // Write info to output files fprintf(fp,"RegClass: %s\n",_classid); const char *name; for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) { ((RegDef*)_regDef[name])->output(fp); } fprintf(fp,"--- done with entries for reg_class %s\n\n",_classid); } //------------------------------AllocClass------------------------------------- AllocClass::AllocClass(char *classid) : _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { } // record a register in this class void AllocClass::addReg(RegDef *regDef) { assert( regDef != NULL, "Can not add a NULL to an allocation class"); regDef->set_register_num( RegisterForm::_reg_ctr++ ); // Add regDef to this allocation class _regDefs.addName(regDef->_regname); _regDef.Insert((void*)regDef->_regname, regDef); } void AllocClass::dump() { output(stderr); } void AllocClass::output(FILE *fp) { // Write info to output files fprintf(fp,"AllocClass: %s \n",_classid); const char *name; for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) { ((RegDef*)_regDef[name])->output(fp); } fprintf(fp,"--- done with entries for alloc_class %s\n\n",_classid); } //==============================Frame Handling================================= //------------------------------FrameForm-------------------------------------- FrameForm::FrameForm() { _frame_pointer = NULL; _c_frame_pointer = NULL; _alignment = NULL; _return_addr = NULL; _c_return_addr = NULL; _in_preserve_slots = NULL; _varargs_C_out_slots_killed = NULL; _calling_convention = NULL; _c_calling_convention = NULL; _return_value = NULL; _c_return_value = NULL; _interpreter_frame_pointer_reg = NULL; } FrameForm::~FrameForm() { } void FrameForm::dump() { output(stderr); } void FrameForm::output(FILE *fp) { // Write info to output files fprintf(fp,"\nFrame:\n"); } //==============================Scheduling===================================== //------------------------------PipelineForm----------------------------------- PipelineForm::PipelineForm() : _reslist () , _resdict (cmpstr, hashstr, Form::arena) , _classdict (cmpstr, hashstr, Form::arena) , _rescount (0) , _maxcycleused (0) , _stages () , _stagecnt (0) , _classlist () , _classcnt (0) , _noplist () , _nopcnt (0) , _variableSizeInstrs (false) , _branchHasDelaySlot (false) , _maxInstrsPerBundle (0) , _maxBundlesPerCycle (1) , _instrUnitSize (0) , _bundleUnitSize (0) , _instrFetchUnitSize (0) , _instrFetchUnits (0) { } PipelineForm::~PipelineForm() { } void PipelineForm::dump() { output(stderr); } void PipelineForm::output(FILE *fp) { // Write info to output files const char *res; const char *stage; const char *cls; const char *nop; int count = 0; fprintf(fp,"\nPipeline:"); if (_variableSizeInstrs) if (_instrUnitSize > 0) fprintf(fp," variable-sized instructions in %d byte units", _instrUnitSize); else fprintf(fp," variable-sized instructions"); else if (_instrUnitSize > 0) fprintf(fp," fixed-sized instructions of %d bytes", _instrUnitSize); else if (_bundleUnitSize > 0) fprintf(fp," fixed-sized bundles of %d bytes", _bundleUnitSize); else fprintf(fp," fixed-sized instructions"); if (_branchHasDelaySlot) fprintf(fp,", branch has delay slot"); if (_maxInstrsPerBundle > 0) fprintf(fp,", max of %d instruction%s in parallel", _maxInstrsPerBundle, _maxInstrsPerBundle > 1 ? "s" : ""); if (_maxBundlesPerCycle > 0) fprintf(fp,", max of %d bundle%s in parallel", _maxBundlesPerCycle, _maxBundlesPerCycle > 1 ? "s" : ""); if (_instrFetchUnitSize > 0 && _instrFetchUnits) fprintf(fp, ", fetch %d x % d bytes per cycle", _instrFetchUnits, _instrFetchUnitSize); fprintf(fp,"\nResource:"); for ( _reslist.reset(); (res = _reslist.iter()) != NULL; ) fprintf(fp," %s(0x%08x)", res, _resdict[res]->is_resource()->mask()); fprintf(fp,"\n"); fprintf(fp,"\nDescription:\n"); for ( _stages.reset(); (stage = _stages.iter()) != NULL; ) fprintf(fp," %s(%d)", stage, count++); fprintf(fp,"\n"); fprintf(fp,"\nClasses:\n"); for ( _classlist.reset(); (cls = _classlist.iter()) != NULL; ) _classdict[cls]->is_pipeclass()->output(fp); fprintf(fp,"\nNop Instructions:"); for ( _noplist.reset(); (nop = _noplist.iter()) != NULL; ) fprintf(fp, " \"%s\"", nop); fprintf(fp,"\n"); } //------------------------------ResourceForm----------------------------------- ResourceForm::ResourceForm(unsigned resmask) : _resmask(resmask) { } ResourceForm::~ResourceForm() { } ResourceForm *ResourceForm::is_resource() const { return (ResourceForm *)(this); } void ResourceForm::dump() { output(stderr); } void ResourceForm::output(FILE *fp) { // Write info to output files fprintf(fp, "resource: 0x%08x;\n", mask()); } //------------------------------PipeClassOperandForm---------------------------------- void PipeClassOperandForm::dump() { output(stderr); } void PipeClassOperandForm::output(FILE *fp) { // Write info to output files fprintf(stderr,"PipeClassOperandForm: %s", _stage); fflush(stderr); if (_more_instrs > 0) fprintf(stderr,"+%d", _more_instrs); fprintf(stderr," (%s)\n", _iswrite ? "write" : "read"); fflush(stderr); fprintf(fp,"PipeClassOperandForm: %s", _stage); if (_more_instrs > 0) fprintf(fp,"+%d", _more_instrs); fprintf(fp," (%s)\n", _iswrite ? "write" : "read"); } //------------------------------PipeClassResourceForm---------------------------------- void PipeClassResourceForm::dump() { output(stderr); } void PipeClassResourceForm::output(FILE *fp) { // Write info to output files fprintf(fp,"PipeClassResourceForm: %s at stage %s for %d cycles\n", _resource, _stage, _cycles); } //------------------------------PipeClassForm---------------------------------- PipeClassForm::PipeClassForm(const char *id, int num) : _ident(id) , _num(num) , _localNames(cmpstr, hashstr, Form::arena) , _localUsage(cmpstr, hashstr, Form::arena) , _has_fixed_latency(0) , _fixed_latency(0) , _instruction_count(0) , _has_multiple_bundles(false) , _has_branch_delay_slot(false) , _force_serialization(false) , _may_have_no_code(false) { } PipeClassForm::~PipeClassForm() { } PipeClassForm *PipeClassForm::is_pipeclass() const { return (PipeClassForm *)(this); } void PipeClassForm::dump() { output(stderr); } void PipeClassForm::output(FILE *fp) { // Write info to output files fprintf(fp,"PipeClassForm: #%03d", _num); if (_ident) fprintf(fp," \"%s\":", _ident); if (_has_fixed_latency) fprintf(fp," latency %d", _fixed_latency); if (_force_serialization) fprintf(fp, ", force serialization"); if (_may_have_no_code) fprintf(fp, ", may have no code"); fprintf(fp, ", %d instruction%s\n", InstructionCount(), InstructionCount() != 1 ? "s" : ""); } //==============================Peephole Optimization========================== int Peephole::_peephole_counter = 0; //------------------------------Peephole--------------------------------------- Peephole::Peephole() : _match(NULL), _constraint(NULL), _replace(NULL), _next(NULL) { _peephole_number = _peephole_counter++; } Peephole::~Peephole() { } // Append a peephole rule with the same root instruction void Peephole::append_peephole(Peephole *next_peephole) { if( _next == NULL ) { _next = next_peephole; } else { _next->append_peephole( next_peephole ); } } // Store the components of this peephole rule void Peephole::add_match(PeepMatch *match) { assert( _match == NULL, "fatal()" ); _match = match; } void Peephole::append_constraint(PeepConstraint *next_constraint) { if( _constraint == NULL ) { _constraint = next_constraint; } else { _constraint->append( next_constraint ); } } void Peephole::add_replace(PeepReplace *replace) { assert( _replace == NULL, "fatal()" ); _replace = replace; } // class Peephole accessor methods are in the declaration. void Peephole::dump() { output(stderr); } void Peephole::output(FILE *fp) { // Write info to output files fprintf(fp,"Peephole:\n"); if( _match != NULL ) _match->output(fp); if( _constraint != NULL ) _constraint->output(fp); if( _replace != NULL ) _replace->output(fp); // Output the next entry if( _next ) _next->output(fp); } //------------------------------PeepMatch-------------------------------------- PeepMatch::PeepMatch(char *rule) : _max_position(0), _rule(rule) { } PeepMatch::~PeepMatch() { } // Insert info into the match-rule void PeepMatch::add_instruction(int parent, int position, const char *name, int input) { if( position > _max_position ) _max_position = position; _parent.addName((char*) (intptr_t) parent); _position.addName((char*) (intptr_t) position); _instrs.addName(name); _input.addName((char*) (intptr_t) input); } // Access info about instructions in the peep-match rule int PeepMatch::max_position() { return _max_position; } const char *PeepMatch::instruction_name(int position) { return _instrs.name(position); } // Iterate through all info on matched instructions void PeepMatch::reset() { _parent.reset(); _position.reset(); _instrs.reset(); _input.reset(); } void PeepMatch::next_instruction(int &parent, int &position, const char* &name, int &input) { parent = (int) (intptr_t) _parent.iter(); position = (int) (intptr_t) _position.iter(); name = _instrs.iter(); input = (int) (intptr_t) _input.iter(); } // 'true' if current position in iteration is a placeholder, not matched. bool PeepMatch::is_placeholder() { return _instrs.current_is_signal(); } void PeepMatch::dump() { output(stderr); } void PeepMatch::output(FILE *fp) { // Write info to output files fprintf(fp,"PeepMatch:\n"); } //------------------------------PeepConstraint--------------------------------- PeepConstraint::PeepConstraint(int left_inst, char* left_op, char* relation, int right_inst, char* right_op) : _left_inst(left_inst), _left_op(left_op), _relation(relation), _right_inst(right_inst), _right_op(right_op), _next(NULL) {} PeepConstraint::~PeepConstraint() { } // Check if constraints use instruction at position bool PeepConstraint::constrains_instruction(int position) { // Check local instruction constraints if( _left_inst == position ) return true; if( _right_inst == position ) return true; // Check remaining constraints in list if( _next == NULL ) return false; else return _next->constrains_instruction(position); } // Add another constraint void PeepConstraint::append(PeepConstraint *next_constraint) { if( _next == NULL ) { _next = next_constraint; } else { _next->append( next_constraint ); } } // Access the next constraint in the list PeepConstraint *PeepConstraint::next() { return _next; } void PeepConstraint::dump() { output(stderr); } void PeepConstraint::output(FILE *fp) { // Write info to output files fprintf(fp,"PeepConstraint:\n"); } //------------------------------PeepReplace------------------------------------ PeepReplace::PeepReplace(char *rule) : _rule(rule) { } PeepReplace::~PeepReplace() { } // Add contents of peepreplace void PeepReplace::add_instruction(char *root) { _instruction.addName(root); _operand_inst_num.add_signal(); _operand_op_name.add_signal(); } void PeepReplace::add_operand( int inst_num, char *inst_operand ) { _instruction.add_signal(); _operand_inst_num.addName((char*) (intptr_t) inst_num); _operand_op_name.addName(inst_operand); } // Access contents of peepreplace void PeepReplace::reset() { _instruction.reset(); _operand_inst_num.reset(); _operand_op_name.reset(); } void PeepReplace::next_instruction(const char* &inst){ inst = _instruction.iter(); int inst_num = (int) (intptr_t) _operand_inst_num.iter(); const char* inst_operand = _operand_op_name.iter(); } void PeepReplace::next_operand(int &inst_num, const char* &inst_operand) { const char* inst = _instruction.iter(); inst_num = (int) (intptr_t) _operand_inst_num.iter(); inst_operand = _operand_op_name.iter(); } void PeepReplace::dump() { output(stderr); } void PeepReplace::output(FILE *fp) { // Write info to output files fprintf(fp,"PeepReplace:\n"); }