| /* |
| * Copyright (c) 1998, 2012, 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 |
| template <typename T> |
| T* RegisterForm::addRegClass(const char* className) { |
| T* regClass = new T(className); |
| _rclasses.addName(className); |
| _regClass.Insert(className, regClass); |
| return regClass; |
| } |
| |
| // Explicit instantiation for all supported register classes. |
| template RegClass* RegisterForm::addRegClass<RegClass>(const char* className); |
| template CodeSnippetRegClass* RegisterForm::addRegClass<CodeSnippetRegClass>(const char* className); |
| template ConditionalRegClass* RegisterForm::addRegClass<ConditionalRegClass>(const char* className); |
| |
| // 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+7) & ~7; |
| const char *rc_name = "stack_slots"; |
| RegClass* reg_class = new RegClass(rc_name); |
| reg_class->set_stack_version(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; |
| // The array of Register Mask bits should be large enough to cover |
| // all the machine registers and all parameters that need to be passed |
| // on the stack (stack registers) up to some interesting limit. Methods |
| // that need more parameters will NOT be compiled. On Intel, the limit |
| // is something like 90+ parameters. |
| // Add a few (3 words == 96 bits) for incoming & outgoing arguments to calls. |
| // Round up to the next doubleword size. |
| return (words_for_regs + 3 + 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) { |
| } |
| |
| RegClass::~RegClass() { |
| } |
| |
| // 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); |
| } |
| |
| void RegClass::declare_register_masks(FILE* fp) { |
| const char* prefix = ""; |
| const char* rc_name_to_upper = toUpper(_classid); |
| fprintf(fp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); |
| fprintf(fp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); |
| if (_stack_or_reg) { |
| fprintf(fp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); |
| fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); |
| } |
| delete[] rc_name_to_upper; |
| } |
| |
| void RegClass::build_register_masks(FILE* fp) { |
| int len = RegisterForm::RegMask_Size(); |
| const char *prefix = ""; |
| const char* rc_name_to_upper = toUpper(_classid); |
| fprintf(fp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); |
| |
| int i; |
| for(i = 0; i < len - 1; i++) { |
| fprintf(fp," 0x%x,", regs_in_word(i, false)); |
| } |
| fprintf(fp," 0x%x );\n", regs_in_word(i, false)); |
| |
| if (_stack_or_reg) { |
| fprintf(fp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); |
| for(i = 0; i < len - 1; i++) { |
| fprintf(fp," 0x%x,", regs_in_word(i, true)); |
| } |
| fprintf(fp," 0x%x );\n", regs_in_word(i, true)); |
| } |
| delete[] rc_name_to_upper; |
| } |
| |
| //------------------------------CodeSnippetRegClass--------------------------- |
| CodeSnippetRegClass::CodeSnippetRegClass(const char* classid) : RegClass(classid), _code_snippet(NULL) { |
| } |
| |
| CodeSnippetRegClass::~CodeSnippetRegClass() { |
| delete _code_snippet; |
| } |
| |
| void CodeSnippetRegClass::declare_register_masks(FILE* fp) { |
| const char* prefix = ""; |
| const char* rc_name_to_upper = toUpper(_classid); |
| fprintf(fp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, _code_snippet); |
| delete[] rc_name_to_upper; |
| } |
| |
| //------------------------------ConditionalRegClass--------------------------- |
| ConditionalRegClass::ConditionalRegClass(const char *classid) : RegClass(classid), _condition_code(NULL) { |
| } |
| |
| ConditionalRegClass::~ConditionalRegClass() { |
| delete _condition_code; |
| } |
| |
| void ConditionalRegClass::declare_register_masks(FILE* fp) { |
| const char* prefix = ""; |
| const char* rc_name_to_upper = toUpper(_classid); |
| const char* rclass_0_to_upper = toUpper(_rclasses[0]->_classid); |
| const char* rclass_1_to_upper = toUpper(_rclasses[1]->_classid); |
| fprintf(fp, "inline const RegMask &%s%s_mask() {" |
| " return (%s) ?" |
| " %s%s_mask() :" |
| " %s%s_mask(); }\n", |
| prefix, rc_name_to_upper, |
| _condition_code, |
| prefix, rclass_0_to_upper, |
| prefix, rclass_1_to_upper); |
| if (_stack_or_reg) { |
| fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() {" |
| " return (%s) ?" |
| " %sSTACK_OR_%s_mask() :" |
| " %sSTACK_OR_%s_mask(); }\n", |
| prefix, rc_name_to_upper, |
| _condition_code, |
| prefix, rclass_0_to_upper, |
| prefix, rclass_1_to_upper); |
| } |
| delete[] rc_name_to_upper; |
| delete[] rclass_0_to_upper; |
| delete[] rclass_1_to_upper; |
| return; |
| } |
| |
| //------------------------------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"); |
| } |