Path: blob/master/src/hotspot/share/adlc/formssel.cpp
41145 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324// FORMS.CPP - Definitions for ADL Parser Forms Classes25#include "adlc.hpp"2627//==============================Instructions===================================28//------------------------------InstructForm-----------------------------------29InstructForm::InstructForm(const char *id, bool ideal_only)30: _ident(id), _ideal_only(ideal_only),31_localNames(cmpstr, hashstr, Form::arena),32_effects(cmpstr, hashstr, Form::arena),33_is_mach_constant(false),34_needs_constant_base(false),35_has_call(false)36{37_ftype = Form::INS;3839_matrule = NULL;40_insencode = NULL;41_constant = NULL;42_is_postalloc_expand = false;43_opcode = NULL;44_size = NULL;45_attribs = NULL;46_predicate = NULL;47_exprule = NULL;48_rewrule = NULL;49_format = NULL;50_peephole = NULL;51_ins_pipe = NULL;52_uniq_idx = NULL;53_num_uniq = 0;54_cisc_spill_operand = Not_cisc_spillable;// Which operand may cisc-spill55_cisc_spill_alternate = NULL; // possible cisc replacement56_cisc_reg_mask_name = NULL;57_is_cisc_alternate = false;58_is_short_branch = false;59_short_branch_form = NULL;60_alignment = 1;61}6263InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)64: _ident(id), _ideal_only(false),65_localNames(instr->_localNames),66_effects(instr->_effects),67_is_mach_constant(false),68_needs_constant_base(false),69_has_call(false)70{71_ftype = Form::INS;7273_matrule = rule;74_insencode = instr->_insencode;75_constant = instr->_constant;76_is_postalloc_expand = instr->_is_postalloc_expand;77_opcode = instr->_opcode;78_size = instr->_size;79_attribs = instr->_attribs;80_predicate = instr->_predicate;81_exprule = instr->_exprule;82_rewrule = instr->_rewrule;83_format = instr->_format;84_peephole = instr->_peephole;85_ins_pipe = instr->_ins_pipe;86_uniq_idx = instr->_uniq_idx;87_num_uniq = instr->_num_uniq;88_cisc_spill_operand = Not_cisc_spillable; // Which operand may cisc-spill89_cisc_spill_alternate = NULL; // possible cisc replacement90_cisc_reg_mask_name = NULL;91_is_cisc_alternate = false;92_is_short_branch = false;93_short_branch_form = NULL;94_alignment = 1;95// Copy parameters96const char *name;97instr->_parameters.reset();98for (; (name = instr->_parameters.iter()) != NULL;)99_parameters.addName(name);100}101102InstructForm::~InstructForm() {103}104105InstructForm *InstructForm::is_instruction() const {106return (InstructForm*)this;107}108109bool InstructForm::ideal_only() const {110return _ideal_only;111}112113bool InstructForm::sets_result() const {114return (_matrule != NULL && _matrule->sets_result());115}116117bool InstructForm::needs_projections() {118_components.reset();119for( Component *comp; (comp = _components.iter()) != NULL; ) {120if (comp->isa(Component::KILL)) {121return true;122}123}124return false;125}126127128bool InstructForm::has_temps() {129if (_matrule) {130// Examine each component to see if it is a TEMP131_components.reset();132// Skip the first component, if already handled as (SET dst (...))133Component *comp = NULL;134if (sets_result()) comp = _components.iter();135while ((comp = _components.iter()) != NULL) {136if (comp->isa(Component::TEMP)) {137return true;138}139}140}141142return false;143}144145uint InstructForm::num_defs_or_kills() {146uint defs_or_kills = 0;147148_components.reset();149for( Component *comp; (comp = _components.iter()) != NULL; ) {150if( comp->isa(Component::DEF) || comp->isa(Component::KILL) ) {151++defs_or_kills;152}153}154155return defs_or_kills;156}157158// This instruction has an expand rule?159bool InstructForm::expands() const {160return ( _exprule != NULL );161}162163// This instruction has a late expand rule?164bool InstructForm::postalloc_expands() const {165return _is_postalloc_expand;166}167168// This instruction has a peephole rule?169Peephole *InstructForm::peepholes() const {170return _peephole;171}172173// This instruction has a peephole rule?174void InstructForm::append_peephole(Peephole *peephole) {175if( _peephole == NULL ) {176_peephole = peephole;177} else {178_peephole->append_peephole(peephole);179}180}181182183// ideal opcode enumeration184const char *InstructForm::ideal_Opcode( FormDict &globalNames ) const {185if( !_matrule ) return "Node"; // Something weird186// Chain rules do not really have ideal Opcodes; use their source187// operand ideal Opcode instead.188if( is_simple_chain_rule(globalNames) ) {189const char *src = _matrule->_rChild->_opType;190OperandForm *src_op = globalNames[src]->is_operand();191assert( src_op, "Not operand class of chain rule" );192if( !src_op->_matrule ) return "Node";193return src_op->_matrule->_opType;194}195// Operand chain rules do not really have ideal Opcodes196if( _matrule->is_chain_rule(globalNames) )197return "Node";198return strcmp(_matrule->_opType,"Set")199? _matrule->_opType200: _matrule->_rChild->_opType;201}202203// Recursive check on all operands' match rules in my match rule204bool InstructForm::is_pinned(FormDict &globals) {205if ( ! _matrule) return false;206207int index = 0;208if (_matrule->find_type("Goto", index)) return true;209if (_matrule->find_type("If", index)) return true;210if (_matrule->find_type("CountedLoopEnd",index)) return true;211if (_matrule->find_type("Return", index)) return true;212if (_matrule->find_type("Rethrow", index)) return true;213if (_matrule->find_type("TailCall", index)) return true;214if (_matrule->find_type("TailJump", index)) return true;215if (_matrule->find_type("Halt", index)) return true;216if (_matrule->find_type("Jump", index)) return true;217218return is_parm(globals);219}220221// Recursive check on all operands' match rules in my match rule222bool InstructForm::is_projection(FormDict &globals) {223if ( ! _matrule) return false;224225int index = 0;226if (_matrule->find_type("Goto", index)) return true;227if (_matrule->find_type("Return", index)) return true;228if (_matrule->find_type("Rethrow", index)) return true;229if (_matrule->find_type("TailCall",index)) return true;230if (_matrule->find_type("TailJump",index)) return true;231if (_matrule->find_type("Halt", index)) return true;232233return false;234}235236// Recursive check on all operands' match rules in my match rule237bool InstructForm::is_parm(FormDict &globals) {238if ( ! _matrule) return false;239240int index = 0;241if (_matrule->find_type("Parm",index)) return true;242243return false;244}245246bool InstructForm::is_ideal_negD() const {247return (_matrule && _matrule->_rChild && strcmp(_matrule->_rChild->_opType, "NegD") == 0);248}249250// Return 'true' if this instruction matches an ideal 'Copy*' node251int InstructForm::is_ideal_copy() const {252return _matrule ? _matrule->is_ideal_copy() : 0;253}254255// Return 'true' if this instruction is too complex to rematerialize.256int InstructForm::is_expensive() const {257// We can prove it is cheap if it has an empty encoding.258// This helps with platform-specific nops like ThreadLocal and RoundFloat.259if (is_empty_encoding())260return 0;261262if (is_tls_instruction())263return 1;264265if (_matrule == NULL) return 0;266267return _matrule->is_expensive();268}269270// Has an empty encoding if _size is a constant zero or there271// are no ins_encode tokens.272int InstructForm::is_empty_encoding() const {273if (_insencode != NULL) {274_insencode->reset();275if (_insencode->encode_class_iter() == NULL) {276return 1;277}278}279if (_size != NULL && strcmp(_size, "0") == 0) {280return 1;281}282return 0;283}284285int InstructForm::is_tls_instruction() const {286if (_ident != NULL &&287( ! strcmp( _ident,"tlsLoadP") ||288! strncmp(_ident,"tlsLoadP_",9)) ) {289return 1;290}291292if (_matrule != NULL && _insencode != NULL) {293const char* opType = _matrule->_opType;294if (strcmp(opType, "Set")==0)295opType = _matrule->_rChild->_opType;296if (strcmp(opType,"ThreadLocal")==0) {297fprintf(stderr, "Warning: ThreadLocal instruction %s should be named 'tlsLoadP_*'\n",298(_ident == NULL ? "NULL" : _ident));299return 1;300}301}302303return 0;304}305306307// Return 'true' if this instruction matches an ideal 'If' node308bool InstructForm::is_ideal_if() const {309if( _matrule == NULL ) return false;310311return _matrule->is_ideal_if();312}313314// Return 'true' if this instruction matches an ideal 'FastLock' node315bool InstructForm::is_ideal_fastlock() const {316if( _matrule == NULL ) return false;317318return _matrule->is_ideal_fastlock();319}320321// Return 'true' if this instruction matches an ideal 'MemBarXXX' node322bool InstructForm::is_ideal_membar() const {323if( _matrule == NULL ) return false;324325return _matrule->is_ideal_membar();326}327328// Return 'true' if this instruction matches an ideal 'LoadPC' node329bool InstructForm::is_ideal_loadPC() const {330if( _matrule == NULL ) return false;331332return _matrule->is_ideal_loadPC();333}334335// Return 'true' if this instruction matches an ideal 'Box' node336bool InstructForm::is_ideal_box() const {337if( _matrule == NULL ) return false;338339return _matrule->is_ideal_box();340}341342// Return 'true' if this instruction matches an ideal 'Goto' node343bool InstructForm::is_ideal_goto() const {344if( _matrule == NULL ) return false;345346return _matrule->is_ideal_goto();347}348349// Return 'true' if this instruction matches an ideal 'Jump' node350bool InstructForm::is_ideal_jump() const {351if( _matrule == NULL ) return false;352353return _matrule->is_ideal_jump();354}355356// Return 'true' if instruction matches ideal 'If' | 'Goto' | 'CountedLoopEnd'357bool InstructForm::is_ideal_branch() const {358if( _matrule == NULL ) return false;359360return _matrule->is_ideal_if() || _matrule->is_ideal_goto();361}362363364// Return 'true' if this instruction matches an ideal 'Return' node365bool InstructForm::is_ideal_return() const {366if( _matrule == NULL ) return false;367368// Check MatchRule to see if the first entry is the ideal "Return" node369int index = 0;370if (_matrule->find_type("Return",index)) return true;371if (_matrule->find_type("Rethrow",index)) return true;372if (_matrule->find_type("TailCall",index)) return true;373if (_matrule->find_type("TailJump",index)) return true;374375return false;376}377378// Return 'true' if this instruction matches an ideal 'Halt' node379bool InstructForm::is_ideal_halt() const {380int index = 0;381return _matrule && _matrule->find_type("Halt",index);382}383384// Return 'true' if this instruction matches an ideal 'SafePoint' node385bool InstructForm::is_ideal_safepoint() const {386int index = 0;387return _matrule && _matrule->find_type("SafePoint",index);388}389390// Return 'true' if this instruction matches an ideal 'Nop' node391bool InstructForm::is_ideal_nop() const {392return _ident && _ident[0] == 'N' && _ident[1] == 'o' && _ident[2] == 'p' && _ident[3] == '_';393}394395bool InstructForm::is_ideal_control() const {396if ( ! _matrule) return false;397398return is_ideal_return() || is_ideal_branch() || _matrule->is_ideal_jump() || is_ideal_halt();399}400401// Return 'true' if this instruction matches an ideal 'Call' node402Form::CallType InstructForm::is_ideal_call() const {403if( _matrule == NULL ) return Form::invalid_type;404405// Check MatchRule to see if the first entry is the ideal "Call" node406int idx = 0;407if(_matrule->find_type("CallStaticJava",idx)) return Form::JAVA_STATIC;408idx = 0;409if(_matrule->find_type("Lock",idx)) return Form::JAVA_STATIC;410idx = 0;411if(_matrule->find_type("Unlock",idx)) return Form::JAVA_STATIC;412idx = 0;413if(_matrule->find_type("CallDynamicJava",idx)) return Form::JAVA_DYNAMIC;414idx = 0;415if(_matrule->find_type("CallRuntime",idx)) return Form::JAVA_RUNTIME;416idx = 0;417if(_matrule->find_type("CallLeaf",idx)) return Form::JAVA_LEAF;418idx = 0;419if(_matrule->find_type("CallLeafNoFP",idx)) return Form::JAVA_LEAF;420idx = 0;421if(_matrule->find_type("CallLeafVector",idx)) return Form::JAVA_LEAF;422idx = 0;423if(_matrule->find_type("CallNative",idx)) return Form::JAVA_NATIVE;424idx = 0;425426return Form::invalid_type;427}428429// Return 'true' if this instruction matches an ideal 'Load?' node430Form::DataType InstructForm::is_ideal_load() const {431if( _matrule == NULL ) return Form::none;432433return _matrule->is_ideal_load();434}435436// Return 'true' if this instruction matches an ideal 'LoadKlass' node437bool InstructForm::skip_antidep_check() const {438if( _matrule == NULL ) return false;439440return _matrule->skip_antidep_check();441}442443// Return 'true' if this instruction matches an ideal 'Load?' node444Form::DataType InstructForm::is_ideal_store() const {445if( _matrule == NULL ) return Form::none;446447return _matrule->is_ideal_store();448}449450// Return 'true' if this instruction matches an ideal vector node451bool InstructForm::is_vector() const {452if( _matrule == NULL ) return false;453454return _matrule->is_vector();455}456457458// Return the input register that must match the output register459// If this is not required, return 0460uint InstructForm::two_address(FormDict &globals) {461uint matching_input = 0;462if(_components.count() == 0) return 0;463464_components.reset();465Component *comp = _components.iter();466// Check if there is a DEF467if( comp->isa(Component::DEF) ) {468// Check that this is a register469const char *def_type = comp->_type;470const Form *form = globals[def_type];471OperandForm *op = form->is_operand();472if( op ) {473if( op->constrained_reg_class() != NULL &&474op->interface_type(globals) == Form::register_interface ) {475// Remember the local name for equality test later476const char *def_name = comp->_name;477// Check if a component has the same name and is a USE478do {479if( comp->isa(Component::USE) && strcmp(comp->_name,def_name)==0 ) {480return operand_position_format(def_name);481}482} while( (comp = _components.iter()) != NULL);483}484}485}486487return 0;488}489490491// when chaining a constant to an instruction, returns 'true' and sets opType492Form::DataType InstructForm::is_chain_of_constant(FormDict &globals) {493const char *dummy = NULL;494const char *dummy2 = NULL;495return is_chain_of_constant(globals, dummy, dummy2);496}497Form::DataType InstructForm::is_chain_of_constant(FormDict &globals,498const char * &opTypeParam) {499const char *result = NULL;500501return is_chain_of_constant(globals, opTypeParam, result);502}503504Form::DataType InstructForm::is_chain_of_constant(FormDict &globals,505const char * &opTypeParam, const char * &resultParam) {506Form::DataType data_type = Form::none;507if ( ! _matrule) return data_type;508509// !!!!!510// The source of the chain rule is 'position = 1'511uint position = 1;512const char *result = NULL;513const char *name = NULL;514const char *opType = NULL;515// Here base_operand is looking for an ideal type to be returned (opType).516if ( _matrule->is_chain_rule(globals)517&& _matrule->base_operand(position, globals, result, name, opType) ) {518data_type = ideal_to_const_type(opType);519520// if it isn't an ideal constant type, just return521if ( data_type == Form::none ) return data_type;522523// Ideal constant types also adjust the opType parameter.524resultParam = result;525opTypeParam = opType;526return data_type;527}528529return data_type;530}531532// Check if a simple chain rule533bool InstructForm::is_simple_chain_rule(FormDict &globals) const {534if( _matrule && _matrule->sets_result()535&& _matrule->_rChild->_lChild == NULL536&& globals[_matrule->_rChild->_opType]537&& globals[_matrule->_rChild->_opType]->is_opclass() ) {538return true;539}540return false;541}542543// check for structural rematerialization544bool InstructForm::rematerialize(FormDict &globals, RegisterForm *registers ) {545bool rematerialize = false;546547Form::DataType data_type = is_chain_of_constant(globals);548if( data_type != Form::none )549rematerialize = true;550551// Constants552if( _components.count() == 1 && _components[0]->is(Component::USE_DEF) )553rematerialize = true;554555// Pseudo-constants (values easily available to the runtime)556if (is_empty_encoding() && is_tls_instruction())557rematerialize = true;558559// 1-input, 1-output, such as copies or increments.560if( _components.count() == 2 &&561_components[0]->is(Component::DEF) &&562_components[1]->isa(Component::USE) )563rematerialize = true;564565// Check for an ideal 'Load?' and eliminate rematerialize option566if ( is_ideal_load() != Form::none || // Ideal load? Do not rematerialize567is_ideal_copy() != Form::none || // Ideal copy? Do not rematerialize568is_expensive() != Form::none) { // Expensive? Do not rematerialize569rematerialize = false;570}571572// Always rematerialize the flags. They are more expensive to save &573// restore than to recompute (and possibly spill the compare's inputs).574if( _components.count() >= 1 ) {575Component *c = _components[0];576const Form *form = globals[c->_type];577OperandForm *opform = form->is_operand();578if( opform ) {579// Avoid the special stack_slots register classes580const char *rc_name = opform->constrained_reg_class();581if( rc_name ) {582if( strcmp(rc_name,"stack_slots") ) {583// Check for ideal_type of RegFlags584const char *type = opform->ideal_type( globals, registers );585if( (type != NULL) && !strcmp(type, "RegFlags") )586rematerialize = true;587} else588rematerialize = false; // Do not rematerialize things target stk589}590}591}592593return rematerialize;594}595596// loads from memory, so must check for anti-dependence597bool InstructForm::needs_anti_dependence_check(FormDict &globals) const {598if ( skip_antidep_check() ) return false;599600// Machine independent loads must be checked for anti-dependences601if( is_ideal_load() != Form::none ) return true;602603// !!!!! !!!!! !!!!!604// TEMPORARY605// if( is_simple_chain_rule(globals) ) return false;606607// String.(compareTo/equals/indexOf) and Arrays.equals use many memorys edges,608// but writes none609if( _matrule && _matrule->_rChild &&610( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||611strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||612strcmp(_matrule->_rChild->_opType,"StrIndexOf" )==0 ||613strcmp(_matrule->_rChild->_opType,"StrIndexOfChar" )==0 ||614strcmp(_matrule->_rChild->_opType,"HasNegatives" )==0 ||615strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ))616return true;617618// Check if instruction has a USE of a memory operand class, but no defs619bool USE_of_memory = false;620bool DEF_of_memory = false;621Component *comp = NULL;622ComponentList &components = (ComponentList &)_components;623624components.reset();625while( (comp = components.iter()) != NULL ) {626const Form *form = globals[comp->_type];627if( !form ) continue;628OpClassForm *op = form->is_opclass();629if( !op ) continue;630if( form->interface_type(globals) == Form::memory_interface ) {631if( comp->isa(Component::USE) ) USE_of_memory = true;632if( comp->isa(Component::DEF) ) {633OperandForm *oper = form->is_operand();634if( oper && oper->is_user_name_for_sReg() ) {635// Stack slots are unaliased memory handled by allocator636oper = oper; // debug stopping point !!!!!637} else {638DEF_of_memory = true;639}640}641}642}643return (USE_of_memory && !DEF_of_memory);644}645646647int InstructForm::memory_operand(FormDict &globals) const {648// Machine independent loads must be checked for anti-dependences649// Check if instruction has a USE of a memory operand class, or a def.650int USE_of_memory = 0;651int DEF_of_memory = 0;652const char* last_memory_DEF = NULL; // to test DEF/USE pairing in asserts653const char* last_memory_USE = NULL;654Component *unique = NULL;655Component *comp = NULL;656ComponentList &components = (ComponentList &)_components;657658components.reset();659while( (comp = components.iter()) != NULL ) {660const Form *form = globals[comp->_type];661if( !form ) continue;662OpClassForm *op = form->is_opclass();663if( !op ) continue;664if( op->stack_slots_only(globals) ) continue;665if( form->interface_type(globals) == Form::memory_interface ) {666if( comp->isa(Component::DEF) ) {667last_memory_DEF = comp->_name;668DEF_of_memory++;669unique = comp;670} else if( comp->isa(Component::USE) ) {671if( last_memory_DEF != NULL ) {672assert(0 == strcmp(last_memory_DEF, comp->_name), "every memory DEF is followed by a USE of the same name");673last_memory_DEF = NULL;674}675// Handles same memory being used multiple times in the case of BMI1 instructions.676if (last_memory_USE != NULL) {677if (strcmp(comp->_name, last_memory_USE) != 0) {678USE_of_memory++;679}680} else {681USE_of_memory++;682}683last_memory_USE = comp->_name;684685if (DEF_of_memory == 0) // defs take precedence686unique = comp;687} else {688assert(last_memory_DEF == NULL, "unpaired memory DEF");689}690}691}692assert(last_memory_DEF == NULL, "unpaired memory DEF");693assert(USE_of_memory >= DEF_of_memory, "unpaired memory DEF");694USE_of_memory -= DEF_of_memory; // treat paired DEF/USE as one occurrence695if( (USE_of_memory + DEF_of_memory) > 0 ) {696if( is_simple_chain_rule(globals) ) {697//fprintf(stderr, "Warning: chain rule is not really a memory user.\n");698//((InstructForm*)this)->dump();699// Preceding code prints nothing on sparc and these insns on intel:700// leaP8 leaP32 leaPIdxOff leaPIdxScale leaPIdxScaleOff leaP8 leaP32701// leaPIdxOff leaPIdxScale leaPIdxScaleOff702return NO_MEMORY_OPERAND;703}704705if( DEF_of_memory == 1 ) {706assert(unique != NULL, "");707if( USE_of_memory == 0 ) {708// unique def, no uses709} else {710// // unique def, some uses711// // must return bottom unless all uses match def712// unique = NULL;713#ifdef S390714// This case is important for move instructions on s390x.715// On other platforms (e.g. x86), all uses always match the def.716unique = NULL;717#endif718}719} else if( DEF_of_memory > 0 ) {720// multiple defs, don't care about uses721unique = NULL;722} else if( USE_of_memory == 1) {723// unique use, no defs724assert(unique != NULL, "");725} else if( USE_of_memory > 0 ) {726// multiple uses, no defs727unique = NULL;728} else {729assert(false, "bad case analysis");730}731// process the unique DEF or USE, if there is one732if( unique == NULL ) {733return MANY_MEMORY_OPERANDS;734} else {735int pos = components.operand_position(unique->_name);736if( unique->isa(Component::DEF) ) {737pos += 1; // get corresponding USE from DEF738}739assert(pos >= 1, "I was just looking at it!");740return pos;741}742}743744// missed the memory op??745if( true ) { // %%% should not be necessary746if( is_ideal_store() != Form::none ) {747fprintf(stderr, "Warning: cannot find memory opnd in instr.\n");748((InstructForm*)this)->dump();749// pretend it has multiple defs and uses750return MANY_MEMORY_OPERANDS;751}752if( is_ideal_load() != Form::none ) {753fprintf(stderr, "Warning: cannot find memory opnd in instr.\n");754((InstructForm*)this)->dump();755// pretend it has multiple uses and no defs756return MANY_MEMORY_OPERANDS;757}758}759760return NO_MEMORY_OPERAND;761}762763// This instruction captures the machine-independent bottom_type764// Expected use is for pointer vs oop determination for LoadP765bool InstructForm::captures_bottom_type(FormDict &globals) const {766if (_matrule && _matrule->_rChild &&767(!strcmp(_matrule->_rChild->_opType,"CastPP") || // new result type768!strcmp(_matrule->_rChild->_opType,"CastDD") ||769!strcmp(_matrule->_rChild->_opType,"CastFF") ||770!strcmp(_matrule->_rChild->_opType,"CastII") ||771!strcmp(_matrule->_rChild->_opType,"CastLL") ||772!strcmp(_matrule->_rChild->_opType,"CastVV") ||773!strcmp(_matrule->_rChild->_opType,"CastX2P") || // new result type774!strcmp(_matrule->_rChild->_opType,"DecodeN") ||775!strcmp(_matrule->_rChild->_opType,"EncodeP") ||776!strcmp(_matrule->_rChild->_opType,"DecodeNKlass") ||777!strcmp(_matrule->_rChild->_opType,"EncodePKlass") ||778!strcmp(_matrule->_rChild->_opType,"LoadN") ||779!strcmp(_matrule->_rChild->_opType,"LoadNKlass") ||780!strcmp(_matrule->_rChild->_opType,"CreateEx") || // type of exception781!strcmp(_matrule->_rChild->_opType,"CheckCastPP") ||782!strcmp(_matrule->_rChild->_opType,"GetAndSetP") ||783!strcmp(_matrule->_rChild->_opType,"GetAndSetN") ||784!strcmp(_matrule->_rChild->_opType,"RotateLeft") ||785!strcmp(_matrule->_rChild->_opType,"RotateRight") ||786#if INCLUDE_SHENANDOAHGC787!strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") ||788!strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN") ||789#endif790!strcmp(_matrule->_rChild->_opType,"StrInflatedCopy") ||791!strcmp(_matrule->_rChild->_opType,"VectorMaskGen")||792!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") ||793!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true;794else if ( is_ideal_load() == Form::idealP ) return true;795else if ( is_ideal_store() != Form::none ) return true;796797if (needs_base_oop_edge(globals)) return true;798799if (is_vector()) return true;800if (is_mach_constant()) return true;801802return false;803}804805806// Access instr_cost attribute or return NULL.807const char* InstructForm::cost() {808for (Attribute* cur = _attribs; cur != NULL; cur = (Attribute*)cur->_next) {809if( strcmp(cur->_ident,AttributeForm::_ins_cost) == 0 ) {810return cur->_val;811}812}813return NULL;814}815816// Return count of top-level operands.817uint InstructForm::num_opnds() {818int num_opnds = _components.num_operands();819820// Need special handling for matching some ideal nodes821// i.e. Matching a return node822/*823if( _matrule ) {824if( strcmp(_matrule->_opType,"Return" )==0 ||825strcmp(_matrule->_opType,"Halt" )==0 )826return 3;827}828*/829return num_opnds;830}831832const char* InstructForm::opnd_ident(int idx) {833return _components.at(idx)->_name;834}835836const char* InstructForm::unique_opnd_ident(uint idx) {837uint i;838for (i = 1; i < num_opnds(); ++i) {839if (unique_opnds_idx(i) == idx) {840break;841}842}843return (_components.at(i) != NULL) ? _components.at(i)->_name : "";844}845846// Return count of unmatched operands.847uint InstructForm::num_post_match_opnds() {848uint num_post_match_opnds = _components.count();849uint num_match_opnds = _components.match_count();850num_post_match_opnds = num_post_match_opnds - num_match_opnds;851852return num_post_match_opnds;853}854855// Return the number of leaves below this complex operand856uint InstructForm::num_consts(FormDict &globals) const {857if ( ! _matrule) return 0;858859// This is a recursive invocation on all operands in the matchrule860return _matrule->num_consts(globals);861}862863// Constants in match rule with specified type864uint InstructForm::num_consts(FormDict &globals, Form::DataType type) const {865if ( ! _matrule) return 0;866867// This is a recursive invocation on all operands in the matchrule868return _matrule->num_consts(globals, type);869}870871872// Return the register class associated with 'leaf'.873const char *InstructForm::out_reg_class(FormDict &globals) {874assert( false, "InstructForm::out_reg_class(FormDict &globals); Not Implemented");875876return NULL;877}878879880881// Lookup the starting position of inputs we are interested in wrt. ideal nodes882uint InstructForm::oper_input_base(FormDict &globals) {883if( !_matrule ) return 1; // Skip control for most nodes884885// Need special handling for matching some ideal nodes886// i.e. Matching a return node887if( strcmp(_matrule->_opType,"Return" )==0 ||888strcmp(_matrule->_opType,"Rethrow" )==0 ||889strcmp(_matrule->_opType,"TailCall" )==0 ||890strcmp(_matrule->_opType,"TailJump" )==0 ||891strcmp(_matrule->_opType,"SafePoint" )==0 ||892strcmp(_matrule->_opType,"Halt" )==0 )893return AdlcVMDeps::Parms; // Skip the machine-state edges894895if( _matrule->_rChild &&896( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ||897strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||898strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||899strcmp(_matrule->_rChild->_opType,"StrInflatedCopy" )==0 ||900strcmp(_matrule->_rChild->_opType,"StrCompressedCopy" )==0 ||901strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 ||902strcmp(_matrule->_rChild->_opType,"StrIndexOfChar")==0 ||903strcmp(_matrule->_rChild->_opType,"HasNegatives")==0 ||904strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) {905// String.(compareTo/equals/indexOf) and Arrays.equals906// and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray907// take 1 control and 1 memory edges.908// Also String.(compressedCopy/inflatedCopy).909return 2;910}911912// Check for handling of 'Memory' input/edge in the ideal world.913// The AD file writer is shielded from knowledge of these edges.914int base = 1; // Skip control915base += _matrule->needs_ideal_memory_edge(globals);916917// Also skip the base-oop value for uses of derived oops.918// The AD file writer is shielded from knowledge of these edges.919base += needs_base_oop_edge(globals);920921return base;922}923924// This function determines the order of the MachOper in _opnds[]925// by writing the operand names into the _components list.926//927// Implementation does not modify state of internal structures928void InstructForm::build_components() {929// Add top-level operands to the components930if (_matrule) _matrule->append_components(_localNames, _components);931932// Add parameters that "do not appear in match rule".933bool has_temp = false;934const char *name;935const char *kill_name = NULL;936for (_parameters.reset(); (name = _parameters.iter()) != NULL;) {937OpClassForm *opForm = _localNames[name]->is_opclass();938assert(opForm != NULL, "sanity");939940Effect* e = NULL;941{942const Form* form = _effects[name];943e = form ? form->is_effect() : NULL;944}945946if (e != NULL) {947has_temp |= e->is(Component::TEMP);948949// KILLs must be declared after any TEMPs because TEMPs are real950// uses so their operand numbering must directly follow the real951// inputs from the match rule. Fixing the numbering seems952// complex so simply enforce the restriction during parse.953if (kill_name != NULL &&954e->isa(Component::TEMP) && !e->isa(Component::DEF)) {955OpClassForm* kill = _localNames[kill_name]->is_opclass();956assert(kill != NULL, "sanity");957globalAD->syntax_err(_linenum, "%s: %s %s must be at the end of the argument list\n",958_ident, kill->_ident, kill_name);959} else if (e->isa(Component::KILL) && !e->isa(Component::USE)) {960kill_name = name;961}962}963964const Component *component = _components.search(name);965if ( component == NULL ) {966if (e) {967_components.insert(name, opForm->_ident, e->_use_def, false);968component = _components.search(name);969if (component->isa(Component::USE) && !component->isa(Component::TEMP) && _matrule) {970const Form *form = globalAD->globalNames()[component->_type];971assert( form, "component type must be a defined form");972OperandForm *op = form->is_operand();973if (op->_interface && op->_interface->is_RegInterface()) {974globalAD->syntax_err(_linenum, "%s: illegal USE of non-input: %s %s\n",975_ident, opForm->_ident, name);976}977}978} else {979// This would be a nice warning but it triggers in a few places in a benign way980// if (_matrule != NULL && !expands()) {981// globalAD->syntax_err(_linenum, "%s: %s %s not mentioned in effect or match rule\n",982// _ident, opForm->_ident, name);983// }984_components.insert(name, opForm->_ident, Component::INVALID, false);985}986}987else if (e) {988// Component was found in the list989// Check if there is a new effect that requires an extra component.990// This happens when adding 'USE' to a component that is not yet one.991if ((!component->isa( Component::USE) && ((e->_use_def & Component::USE) != 0))) {992if (component->isa(Component::USE) && _matrule) {993const Form *form = globalAD->globalNames()[component->_type];994assert( form, "component type must be a defined form");995OperandForm *op = form->is_operand();996if (op->_interface && op->_interface->is_RegInterface()) {997globalAD->syntax_err(_linenum, "%s: illegal USE of non-input: %s %s\n",998_ident, opForm->_ident, name);999}1000}1001_components.insert(name, opForm->_ident, e->_use_def, false);1002} else {1003Component *comp = (Component*)component;1004comp->promote_use_def_info(e->_use_def);1005}1006// Component positions are zero based.1007int pos = _components.operand_position(name);1008assert( ! (component->isa(Component::DEF) && (pos >= 1)),1009"Component::DEF can only occur in the first position");1010}1011}10121013// Resolving the interactions between expand rules and TEMPs would1014// be complex so simply disallow it.1015if (_matrule == NULL && has_temp) {1016globalAD->syntax_err(_linenum, "%s: TEMPs without match rule isn't supported\n", _ident);1017}10181019return;1020}10211022// Return zero-based position in component list; -1 if not in list.1023int InstructForm::operand_position(const char *name, int usedef) {1024return unique_opnds_idx(_components.operand_position(name, usedef, this));1025}10261027int InstructForm::operand_position_format(const char *name) {1028return unique_opnds_idx(_components.operand_position_format(name, this));1029}10301031// Return zero-based position in component list; -1 if not in list.1032int InstructForm::label_position() {1033return unique_opnds_idx(_components.label_position());1034}10351036int InstructForm::method_position() {1037return unique_opnds_idx(_components.method_position());1038}10391040// Return number of relocation entries needed for this instruction.1041uint InstructForm::reloc(FormDict &globals) {1042uint reloc_entries = 0;1043// Check for "Call" nodes1044if ( is_ideal_call() ) ++reloc_entries;1045if ( is_ideal_return() ) ++reloc_entries;1046if ( is_ideal_safepoint() ) ++reloc_entries;104710481049// Check if operands MAYBE oop pointers, by checking for ConP elements1050// Proceed through the leaves of the match-tree and check for ConPs1051if ( _matrule != NULL ) {1052uint position = 0;1053const char *result = NULL;1054const char *name = NULL;1055const char *opType = NULL;1056while (_matrule->base_operand(position, globals, result, name, opType)) {1057if ( strcmp(opType,"ConP") == 0 ) {1058++reloc_entries;1059}1060++position;1061}1062}10631064// Above is only a conservative estimate1065// because it did not check contents of operand classes.1066// !!!!! !!!!!1067// Add 1 to reloc info for each operand class in the component list.1068Component *comp;1069_components.reset();1070while ( (comp = _components.iter()) != NULL ) {1071const Form *form = globals[comp->_type];1072assert( form, "Did not find component's type in global names");1073const OpClassForm *opc = form->is_opclass();1074const OperandForm *oper = form->is_operand();1075if ( opc && (oper == NULL) ) {1076++reloc_entries;1077} else if ( oper ) {1078// floats and doubles loaded out of method's constant pool require reloc info1079Form::DataType type = oper->is_base_constant(globals);1080if ( (type == Form::idealF) || (type == Form::idealD) ) {1081++reloc_entries;1082}1083}1084}10851086// Float and Double constants may come from the CodeBuffer table1087// and require relocatable addresses for access1088// !!!!!1089// Check for any component being an immediate float or double.1090Form::DataType data_type = is_chain_of_constant(globals);1091if( data_type==idealD || data_type==idealF ) {1092reloc_entries++;1093}10941095return reloc_entries;1096}10971098// Utility function defined in archDesc.cpp1099extern bool is_def(int usedef);11001101// Return the result of reducing an instruction1102const char *InstructForm::reduce_result() {1103const char* result = "Universe"; // default1104_components.reset();1105Component *comp = _components.iter();1106if (comp != NULL && comp->isa(Component::DEF)) {1107result = comp->_type;1108// Override this if the rule is a store operation:1109if (_matrule && _matrule->_rChild &&1110is_store_to_memory(_matrule->_rChild->_opType))1111result = "Universe";1112}1113return result;1114}11151116// Return the name of the operand on the right hand side of the binary match1117// Return NULL if there is no right hand side1118const char *InstructForm::reduce_right(FormDict &globals) const {1119if( _matrule == NULL ) return NULL;1120return _matrule->reduce_right(globals);1121}11221123// Similar for left1124const char *InstructForm::reduce_left(FormDict &globals) const {1125if( _matrule == NULL ) return NULL;1126return _matrule->reduce_left(globals);1127}112811291130// Base class for this instruction, MachNode except for calls1131const char *InstructForm::mach_base_class(FormDict &globals) const {1132if( is_ideal_call() == Form::JAVA_STATIC ) {1133return "MachCallStaticJavaNode";1134}1135else if( is_ideal_call() == Form::JAVA_DYNAMIC ) {1136return "MachCallDynamicJavaNode";1137}1138else if( is_ideal_call() == Form::JAVA_RUNTIME ) {1139return "MachCallRuntimeNode";1140}1141else if( is_ideal_call() == Form::JAVA_LEAF ) {1142return "MachCallLeafNode";1143}1144else if( is_ideal_call() == Form::JAVA_NATIVE ) {1145return "MachCallNativeNode";1146}1147else if (is_ideal_return()) {1148return "MachReturnNode";1149}1150else if (is_ideal_halt()) {1151return "MachHaltNode";1152}1153else if (is_ideal_safepoint()) {1154return "MachSafePointNode";1155}1156else if (is_ideal_if()) {1157return "MachIfNode";1158}1159else if (is_ideal_goto()) {1160return "MachGotoNode";1161}1162else if (is_ideal_fastlock()) {1163return "MachFastLockNode";1164}1165else if (is_ideal_nop()) {1166return "MachNopNode";1167}1168else if( is_ideal_membar()) {1169return "MachMemBarNode";1170}1171else if (is_ideal_jump()) {1172return "MachJumpNode";1173}1174else if (is_mach_constant()) {1175return "MachConstantNode";1176}1177else if (captures_bottom_type(globals)) {1178return "MachTypeNode";1179} else {1180return "MachNode";1181}1182assert( false, "ShouldNotReachHere()");1183return NULL;1184}11851186// Compare the instruction predicates for textual equality1187bool equivalent_predicates( const InstructForm *instr1, const InstructForm *instr2 ) {1188const Predicate *pred1 = instr1->_predicate;1189const Predicate *pred2 = instr2->_predicate;1190if( pred1 == NULL && pred2 == NULL ) {1191// no predicates means they are identical1192return true;1193}1194if( pred1 != NULL && pred2 != NULL ) {1195// compare the predicates1196if (ADLParser::equivalent_expressions(pred1->_pred, pred2->_pred)) {1197return true;1198}1199}12001201return false;1202}12031204// Check if this instruction can cisc-spill to 'alternate'1205bool InstructForm::cisc_spills_to(ArchDesc &AD, InstructForm *instr) {1206assert( _matrule != NULL && instr->_matrule != NULL, "must have match rules");1207// Do not replace if a cisc-version has been found.1208if( cisc_spill_operand() != Not_cisc_spillable ) return false;12091210int cisc_spill_operand = Maybe_cisc_spillable;1211char *result = NULL;1212char *result2 = NULL;1213const char *op_name = NULL;1214const char *reg_type = NULL;1215FormDict &globals = AD.globalNames();1216cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type);1217if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != NULL) && equivalent_predicates(this, instr) ) {1218cisc_spill_operand = operand_position(op_name, Component::USE);1219int def_oper = operand_position(op_name, Component::DEF);1220if( def_oper == NameList::Not_in_list && instr->num_opnds() == num_opnds()) {1221// Do not support cisc-spilling for destination operands and1222// make sure they have the same number of operands.1223_cisc_spill_alternate = instr;1224instr->set_cisc_alternate(true);1225if( AD._cisc_spill_debug ) {1226fprintf(stderr, "Instruction %s cisc-spills-to %s\n", _ident, instr->_ident);1227fprintf(stderr, " using operand %s %s at index %d\n", reg_type, op_name, cisc_spill_operand);1228}1229// Record that a stack-version of the reg_mask is needed1230// !!!!!1231OperandForm *oper = (OperandForm*)(globals[reg_type]->is_operand());1232assert( oper != NULL, "cisc-spilling non operand");1233const char *reg_class_name = oper->constrained_reg_class();1234AD.set_stack_or_reg(reg_class_name);1235const char *reg_mask_name = AD.reg_mask(*oper);1236set_cisc_reg_mask_name(reg_mask_name);1237const char *stack_or_reg_mask_name = AD.stack_or_reg_mask(*oper);1238} else {1239cisc_spill_operand = Not_cisc_spillable;1240}1241} else {1242cisc_spill_operand = Not_cisc_spillable;1243}12441245set_cisc_spill_operand(cisc_spill_operand);1246return (cisc_spill_operand != Not_cisc_spillable);1247}12481249// Check to see if this instruction can be replaced with the short branch1250// instruction `short-branch'1251bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch) {1252if (_matrule != NULL &&1253this != short_branch && // Don't match myself1254!is_short_branch() && // Don't match another short branch variant1255reduce_result() != NULL &&1256strstr(_ident, "restoreMask") == NULL && // Don't match side effects1257strcmp(reduce_result(), short_branch->reduce_result()) == 0 &&1258_matrule->equivalent(AD.globalNames(), short_branch->_matrule)) {1259// The instructions are equivalent.12601261// Now verify that both instructions have the same parameters and1262// the same effects. Both branch forms should have the same inputs1263// and resulting projections to correctly replace a long branch node1264// with corresponding short branch node during code generation.12651266bool different = false;1267if (short_branch->_components.count() != _components.count()) {1268different = true;1269} else if (_components.count() > 0) {1270short_branch->_components.reset();1271_components.reset();1272Component *comp;1273while ((comp = _components.iter()) != NULL) {1274Component *short_comp = short_branch->_components.iter();1275if (short_comp == NULL ||1276short_comp->_type != comp->_type ||1277short_comp->_usedef != comp->_usedef) {1278different = true;1279break;1280}1281}1282if (short_branch->_components.iter() != NULL)1283different = true;1284}1285if (different) {1286globalAD->syntax_err(short_branch->_linenum, "Instruction %s and its short form %s have different parameters\n", _ident, short_branch->_ident);1287}1288if (AD._adl_debug > 1 || AD._short_branch_debug) {1289fprintf(stderr, "Instruction %s has short form %s\n", _ident, short_branch->_ident);1290}1291_short_branch_form = short_branch;1292return true;1293}1294return false;1295}129612971298// --------------------------- FILE *output_routines1299//1300// Generate the format call for the replacement variable1301void InstructForm::rep_var_format(FILE *fp, const char *rep_var) {1302// Handle special constant table variables.1303if (strcmp(rep_var, "constanttablebase") == 0) {1304fprintf(fp, "char reg[128]; ra->dump_register(in(mach_constant_base_node_input()), reg);\n");1305fprintf(fp, " st->print(\"%%s\", reg);\n");1306return;1307}1308if (strcmp(rep_var, "constantoffset") == 0) {1309fprintf(fp, "st->print(\"#%%d\", constant_offset_unchecked());\n");1310return;1311}1312if (strcmp(rep_var, "constantaddress") == 0) {1313fprintf(fp, "st->print(\"constant table base + #%%d\", constant_offset_unchecked());\n");1314return;1315}13161317// Find replacement variable's type1318const Form *form = _localNames[rep_var];1319if (form == NULL) {1320globalAD->syntax_err(_linenum, "Unknown replacement variable %s in format statement of %s.",1321rep_var, _ident);1322return;1323}1324OpClassForm *opc = form->is_opclass();1325assert( opc, "replacement variable was not found in local names");1326// Lookup the index position of the replacement variable1327int idx = operand_position_format(rep_var);1328if ( idx == -1 ) {1329globalAD->syntax_err(_linenum, "Could not find replacement variable %s in format statement of %s.\n",1330rep_var, _ident);1331assert(strcmp(opc->_ident, "label") == 0, "Unimplemented");1332return;1333}13341335if (is_noninput_operand(idx)) {1336// This component isn't in the input array. Print out the static1337// name of the register.1338OperandForm* oper = form->is_operand();1339if (oper != NULL && oper->is_bound_register()) {1340const RegDef* first = oper->get_RegClass()->find_first_elem();1341fprintf(fp, " st->print_raw(\"%s\");\n", first->_regname);1342} else {1343globalAD->syntax_err(_linenum, "In %s can't find format for %s %s", _ident, opc->_ident, rep_var);1344}1345} else {1346// Output the format call for this operand1347fprintf(fp,"opnd_array(%d)->",idx);1348if (idx == 0)1349fprintf(fp,"int_format(ra, this, st); // %s\n", rep_var);1350else1351fprintf(fp,"ext_format(ra, this,idx%d, st); // %s\n", idx, rep_var );1352}1353}13541355// Seach through operands to determine parameters unique positions.1356void InstructForm::set_unique_opnds() {1357uint* uniq_idx = NULL;1358uint nopnds = num_opnds();1359uint num_uniq = nopnds;1360uint i;1361_uniq_idx_length = 0;1362if (nopnds > 0) {1363// Allocate index array. Worst case we're mapping from each1364// component back to an index and any DEF always goes at 0 so the1365// length of the array has to be the number of components + 1.1366_uniq_idx_length = _components.count() + 1;1367uniq_idx = (uint*) AllocateHeap(sizeof(uint) * _uniq_idx_length);1368for (i = 0; i < _uniq_idx_length; i++) {1369uniq_idx[i] = i;1370}1371}1372// Do it only if there is a match rule and no expand rule. With an1373// expand rule it is done by creating new mach node in Expand()1374// method.1375if (nopnds > 0 && _matrule != NULL && _exprule == NULL) {1376const char *name;1377uint count;1378bool has_dupl_use = false;13791380_parameters.reset();1381while ((name = _parameters.iter()) != NULL) {1382count = 0;1383uint position = 0;1384uint uniq_position = 0;1385_components.reset();1386Component *comp = NULL;1387if (sets_result()) {1388comp = _components.iter();1389position++;1390}1391// The next code is copied from the method operand_position().1392for (; (comp = _components.iter()) != NULL; ++position) {1393// When the first component is not a DEF,1394// leave space for the result operand!1395if (position==0 && (!comp->isa(Component::DEF))) {1396++position;1397}1398if (strcmp(name, comp->_name) == 0) {1399if (++count > 1) {1400assert(position < _uniq_idx_length, "out of bounds");1401uniq_idx[position] = uniq_position;1402has_dupl_use = true;1403} else {1404uniq_position = position;1405}1406}1407if (comp->isa(Component::DEF) && comp->isa(Component::USE)) {1408++position;1409if (position != 1)1410--position; // only use two slots for the 1st USE_DEF1411}1412}1413}1414if (has_dupl_use) {1415for (i = 1; i < nopnds; i++) {1416if (i != uniq_idx[i]) {1417break;1418}1419}1420uint j = i;1421for (; i < nopnds; i++) {1422if (i == uniq_idx[i]) {1423uniq_idx[i] = j++;1424}1425}1426num_uniq = j;1427}1428}1429_uniq_idx = uniq_idx;1430_num_uniq = num_uniq;1431}14321433// Generate index values needed for determining the operand position1434void InstructForm::index_temps(FILE *fp, FormDict &globals, const char *prefix, const char *receiver) {1435uint idx = 0; // position of operand in match rule1436int cur_num_opnds = num_opnds();14371438// Compute the index into vector of operand pointers:1439// idx0=0 is used to indicate that info comes from this same node, not from input edge.1440// idx1 starts at oper_input_base()1441if ( cur_num_opnds >= 1 ) {1442fprintf(fp," // Start at oper_input_base() and count operands\n");1443fprintf(fp," unsigned %sidx0 = %d;\n", prefix, oper_input_base(globals));1444fprintf(fp," unsigned %sidx1 = %d;", prefix, oper_input_base(globals));1445fprintf(fp," \t// %s\n", unique_opnd_ident(1));14461447// Generate starting points for other unique operands if they exist1448for ( idx = 2; idx < num_unique_opnds(); ++idx ) {1449if( *receiver == 0 ) {1450fprintf(fp," unsigned %sidx%d = %sidx%d + opnd_array(%d)->num_edges();",1451prefix, idx, prefix, idx-1, idx-1 );1452} else {1453fprintf(fp," unsigned %sidx%d = %sidx%d + %s_opnds[%d]->num_edges();",1454prefix, idx, prefix, idx-1, receiver, idx-1 );1455}1456fprintf(fp," \t// %s\n", unique_opnd_ident(idx));1457}1458}1459if( *receiver != 0 ) {1460// This value is used by generate_peepreplace when copying a node.1461// Don't emit it in other cases since it can hide bugs with the1462// use invalid idx's.1463fprintf(fp," unsigned %sidx%d = %sreq(); \n", prefix, idx, receiver);1464}14651466}14671468// ---------------------------1469bool InstructForm::verify() {1470// !!!!! !!!!!1471// Check that a "label" operand occurs last in the operand list, if present1472return true;1473}14741475void InstructForm::dump() {1476output(stderr);1477}14781479void InstructForm::output(FILE *fp) {1480fprintf(fp,"\nInstruction: %s\n", (_ident?_ident:""));1481if (_matrule) _matrule->output(fp);1482if (_insencode) _insencode->output(fp);1483if (_constant) _constant->output(fp);1484if (_opcode) _opcode->output(fp);1485if (_attribs) _attribs->output(fp);1486if (_predicate) _predicate->output(fp);1487if (_effects.Size()) {1488fprintf(fp,"Effects\n");1489_effects.dump();1490}1491if (_exprule) _exprule->output(fp);1492if (_rewrule) _rewrule->output(fp);1493if (_format) _format->output(fp);1494if (_peephole) _peephole->output(fp);1495}14961497void MachNodeForm::dump() {1498output(stderr);1499}15001501void MachNodeForm::output(FILE *fp) {1502fprintf(fp,"\nMachNode: %s\n", (_ident?_ident:""));1503}15041505//------------------------------build_predicate--------------------------------1506// Build instruction predicates. If the user uses the same operand name1507// twice, we need to check that the operands are pointer-eequivalent in1508// the DFA during the labeling process.1509Predicate *InstructForm::build_predicate() {1510const int buflen = 1024;1511char buf[buflen], *s=buf;1512Dict names(cmpstr,hashstr,Form::arena); // Map Names to counts15131514MatchNode *mnode =1515strcmp(_matrule->_opType, "Set") ? _matrule : _matrule->_rChild;1516if (mnode != NULL) mnode->count_instr_names(names);15171518uint first = 1;1519// Start with the predicate supplied in the .ad file.1520if (_predicate) {1521if (first) first = 0;1522strcpy(s, "("); s += strlen(s);1523strncpy(s, _predicate->_pred, buflen - strlen(s) - 1);1524s += strlen(s);1525strcpy(s, ")"); s += strlen(s);1526}1527for( DictI i(&names); i.test(); ++i ) {1528uintptr_t cnt = (uintptr_t)i._value;1529if( cnt > 1 ) { // Need a predicate at all?1530int path_bitmask = 0;1531assert( cnt == 2, "Unimplemented" );1532// Handle many pairs1533if( first ) first=0;1534else { // All tests must pass, so use '&&'1535strcpy(s," && ");1536s += strlen(s);1537}1538// Add predicate to working buffer1539sprintf(s,"/*%s*/(",(char*)i._key);1540s += strlen(s);1541mnode->build_instr_pred(s,(char*)i._key, 0, path_bitmask, 0);1542s += strlen(s);1543strcpy(s," == "); s += strlen(s);1544mnode->build_instr_pred(s,(char*)i._key, 1, path_bitmask, 0);1545s += strlen(s);1546strcpy(s,")"); s += strlen(s);1547}1548}1549if( s == buf ) s = NULL;1550else {1551assert( strlen(buf) < sizeof(buf), "String buffer overflow" );1552s = strdup(buf);1553}1554return new Predicate(s);1555}15561557//------------------------------EncodeForm-------------------------------------1558// Constructor1559EncodeForm::EncodeForm()1560: _encClass(cmpstr,hashstr, Form::arena) {1561}1562EncodeForm::~EncodeForm() {1563}15641565// record a new register class1566EncClass *EncodeForm::add_EncClass(const char *className) {1567EncClass *encClass = new EncClass(className);1568_eclasses.addName(className);1569_encClass.Insert(className,encClass);1570return encClass;1571}15721573// Lookup the function body for an encoding class1574EncClass *EncodeForm::encClass(const char *className) {1575assert( className != NULL, "Must provide a defined encoding name");15761577EncClass *encClass = (EncClass*)_encClass[className];1578return encClass;1579}15801581// Lookup the function body for an encoding class1582const char *EncodeForm::encClassBody(const char *className) {1583if( className == NULL ) return NULL;15841585EncClass *encClass = (EncClass*)_encClass[className];1586assert( encClass != NULL, "Encode Class is missing.");1587encClass->_code.reset();1588const char *code = (const char*)encClass->_code.iter();1589assert( code != NULL, "Found an empty encode class body.");15901591return code;1592}15931594// Lookup the function body for an encoding class1595const char *EncodeForm::encClassPrototype(const char *className) {1596assert( className != NULL, "Encode class name must be non NULL.");15971598return className;1599}16001601void EncodeForm::dump() { // Debug printer1602output(stderr);1603}16041605void EncodeForm::output(FILE *fp) { // Write info to output files1606const char *name;1607fprintf(fp,"\n");1608fprintf(fp,"-------------------- Dump EncodeForm --------------------\n");1609for (_eclasses.reset(); (name = _eclasses.iter()) != NULL;) {1610((EncClass*)_encClass[name])->output(fp);1611}1612fprintf(fp,"-------------------- end EncodeForm --------------------\n");1613}1614//------------------------------EncClass---------------------------------------1615EncClass::EncClass(const char *name)1616: _localNames(cmpstr,hashstr, Form::arena), _name(name) {1617}1618EncClass::~EncClass() {1619}16201621// Add a parameter <type,name> pair1622void EncClass::add_parameter(const char *parameter_type, const char *parameter_name) {1623_parameter_type.addName( parameter_type );1624_parameter_name.addName( parameter_name );1625}16261627// Verify operand types in parameter list1628bool EncClass::check_parameter_types(FormDict &globals) {1629// !!!!!1630return false;1631}16321633// Add the decomposed "code" sections of an encoding's code-block1634void EncClass::add_code(const char *code) {1635_code.addName(code);1636}16371638// Add the decomposed "replacement variables" of an encoding's code-block1639void EncClass::add_rep_var(char *replacement_var) {1640_code.addName(NameList::_signal);1641_rep_vars.addName(replacement_var);1642}16431644// Lookup the function body for an encoding class1645int EncClass::rep_var_index(const char *rep_var) {1646uint position = 0;1647const char *name = NULL;16481649_parameter_name.reset();1650while ( (name = _parameter_name.iter()) != NULL ) {1651if ( strcmp(rep_var,name) == 0 ) return position;1652++position;1653}16541655return -1;1656}16571658// Check after parsing1659bool EncClass::verify() {1660// 1!!!!1661// Check that each replacement variable, '$name' in architecture description1662// is actually a local variable for this encode class, or a reserved name1663// "primary, secondary, tertiary"1664return true;1665}16661667void EncClass::dump() {1668output(stderr);1669}16701671// Write info to output files1672void EncClass::output(FILE *fp) {1673fprintf(fp,"EncClass: %s", (_name ? _name : ""));16741675// Output the parameter list1676_parameter_type.reset();1677_parameter_name.reset();1678const char *type = _parameter_type.iter();1679const char *name = _parameter_name.iter();1680fprintf(fp, " ( ");1681for ( ; (type != NULL) && (name != NULL);1682(type = _parameter_type.iter()), (name = _parameter_name.iter()) ) {1683fprintf(fp, " %s %s,", type, name);1684}1685fprintf(fp, " ) ");16861687// Output the code block1688_code.reset();1689_rep_vars.reset();1690const char *code;1691while ( (code = _code.iter()) != NULL ) {1692if ( _code.is_signal(code) ) {1693// A replacement variable1694const char *rep_var = _rep_vars.iter();1695fprintf(fp,"($%s)", rep_var);1696} else {1697// A section of code1698fprintf(fp,"%s", code);1699}1700}17011702}17031704//------------------------------Opcode-----------------------------------------1705Opcode::Opcode(char *primary, char *secondary, char *tertiary)1706: _primary(primary), _secondary(secondary), _tertiary(tertiary) {1707}17081709Opcode::~Opcode() {1710}17111712Opcode::opcode_type Opcode::as_opcode_type(const char *param) {1713if( strcmp(param,"primary") == 0 ) {1714return Opcode::PRIMARY;1715}1716else if( strcmp(param,"secondary") == 0 ) {1717return Opcode::SECONDARY;1718}1719else if( strcmp(param,"tertiary") == 0 ) {1720return Opcode::TERTIARY;1721}1722return Opcode::NOT_AN_OPCODE;1723}17241725bool Opcode::print_opcode(FILE *fp, Opcode::opcode_type desired_opcode) {1726// Default values previously provided by MachNode::primary()...1727const char *description = NULL;1728const char *value = NULL;1729// Check if user provided any opcode definitions1730// Update 'value' if user provided a definition in the instruction1731switch (desired_opcode) {1732case PRIMARY:1733description = "primary()";1734if( _primary != NULL) { value = _primary; }1735break;1736case SECONDARY:1737description = "secondary()";1738if( _secondary != NULL ) { value = _secondary; }1739break;1740case TERTIARY:1741description = "tertiary()";1742if( _tertiary != NULL ) { value = _tertiary; }1743break;1744default:1745assert( false, "ShouldNotReachHere();");1746break;1747}17481749if (value != NULL) {1750fprintf(fp, "(%s /*%s*/)", value, description);1751}1752return value != NULL;1753}17541755void Opcode::dump() {1756output(stderr);1757}17581759// Write info to output files1760void Opcode::output(FILE *fp) {1761if (_primary != NULL) fprintf(fp,"Primary opcode: %s\n", _primary);1762if (_secondary != NULL) fprintf(fp,"Secondary opcode: %s\n", _secondary);1763if (_tertiary != NULL) fprintf(fp,"Tertiary opcode: %s\n", _tertiary);1764}17651766//------------------------------InsEncode--------------------------------------1767InsEncode::InsEncode() {1768}1769InsEncode::~InsEncode() {1770}17711772// Add "encode class name" and its parameters1773NameAndList *InsEncode::add_encode(char *encoding) {1774assert( encoding != NULL, "Must provide name for encoding");17751776// add_parameter(NameList::_signal);1777NameAndList *encode = new NameAndList(encoding);1778_encoding.addName((char*)encode);17791780return encode;1781}17821783// Access the list of encodings1784void InsEncode::reset() {1785_encoding.reset();1786// _parameter.reset();1787}1788const char* InsEncode::encode_class_iter() {1789NameAndList *encode_class = (NameAndList*)_encoding.iter();1790return ( encode_class != NULL ? encode_class->name() : NULL );1791}1792// Obtain parameter name from zero based index1793const char *InsEncode::rep_var_name(InstructForm &inst, uint param_no) {1794NameAndList *params = (NameAndList*)_encoding.current();1795assert( params != NULL, "Internal Error");1796const char *param = (*params)[param_no];17971798// Remove '$' if parser placed it there.1799return ( param != NULL && *param == '$') ? (param+1) : param;1800}18011802void InsEncode::dump() {1803output(stderr);1804}18051806// Write info to output files1807void InsEncode::output(FILE *fp) {1808NameAndList *encoding = NULL;1809const char *parameter = NULL;18101811fprintf(fp,"InsEncode: ");1812_encoding.reset();18131814while ( (encoding = (NameAndList*)_encoding.iter()) != 0 ) {1815// Output the encoding being used1816fprintf(fp,"%s(", encoding->name() );18171818// Output its parameter list, if any1819bool first_param = true;1820encoding->reset();1821while ( (parameter = encoding->iter()) != 0 ) {1822// Output the ',' between parameters1823if ( ! first_param ) fprintf(fp,", ");1824first_param = false;1825// Output the parameter1826fprintf(fp,"%s", parameter);1827} // done with parameters1828fprintf(fp,") ");1829} // done with encodings18301831fprintf(fp,"\n");1832}18331834//------------------------------Effect-----------------------------------------1835static int effect_lookup(const char *name) {1836if (!strcmp(name, "USE")) return Component::USE;1837if (!strcmp(name, "DEF")) return Component::DEF;1838if (!strcmp(name, "USE_DEF")) return Component::USE_DEF;1839if (!strcmp(name, "KILL")) return Component::KILL;1840if (!strcmp(name, "USE_KILL")) return Component::USE_KILL;1841if (!strcmp(name, "TEMP")) return Component::TEMP;1842if (!strcmp(name, "TEMP_DEF")) return Component::TEMP_DEF;1843if (!strcmp(name, "INVALID")) return Component::INVALID;1844if (!strcmp(name, "CALL")) return Component::CALL;1845assert(false,"Invalid effect name specified\n");1846return Component::INVALID;1847}18481849const char *Component::getUsedefName() {1850switch (_usedef) {1851case Component::INVALID: return "INVALID"; break;1852case Component::USE: return "USE"; break;1853case Component::USE_DEF: return "USE_DEF"; break;1854case Component::USE_KILL: return "USE_KILL"; break;1855case Component::KILL: return "KILL"; break;1856case Component::TEMP: return "TEMP"; break;1857case Component::TEMP_DEF: return "TEMP_DEF"; break;1858case Component::DEF: return "DEF"; break;1859case Component::CALL: return "CALL"; break;1860default: assert(false, "unknown effect");1861}1862return "Undefined Use/Def info";1863}18641865Effect::Effect(const char *name) : _name(name), _use_def(effect_lookup(name)) {1866_ftype = Form::EFF;1867}18681869Effect::~Effect() {1870}18711872// Dynamic type check1873Effect *Effect::is_effect() const {1874return (Effect*)this;1875}187618771878// True if this component is equal to the parameter.1879bool Effect::is(int use_def_kill_enum) const {1880return (_use_def == use_def_kill_enum ? true : false);1881}1882// True if this component is used/def'd/kill'd as the parameter suggests.1883bool Effect::isa(int use_def_kill_enum) const {1884return (_use_def & use_def_kill_enum) == use_def_kill_enum;1885}18861887void Effect::dump() {1888output(stderr);1889}18901891void Effect::output(FILE *fp) { // Write info to output files1892fprintf(fp,"Effect: %s\n", (_name?_name:""));1893}18941895//------------------------------ExpandRule-------------------------------------1896ExpandRule::ExpandRule() : _expand_instrs(),1897_newopconst(cmpstr, hashstr, Form::arena) {1898_ftype = Form::EXP;1899}19001901ExpandRule::~ExpandRule() { // Destructor1902}19031904void ExpandRule::add_instruction(NameAndList *instruction_name_and_operand_list) {1905_expand_instrs.addName((char*)instruction_name_and_operand_list);1906}19071908void ExpandRule::reset_instructions() {1909_expand_instrs.reset();1910}19111912NameAndList* ExpandRule::iter_instructions() {1913return (NameAndList*)_expand_instrs.iter();1914}191519161917void ExpandRule::dump() {1918output(stderr);1919}19201921void ExpandRule::output(FILE *fp) { // Write info to output files1922NameAndList *expand_instr = NULL;1923const char *opid = NULL;19241925fprintf(fp,"\nExpand Rule:\n");19261927// Iterate over the instructions 'node' expands into1928for(reset_instructions(); (expand_instr = iter_instructions()) != NULL; ) {1929fprintf(fp,"%s(", expand_instr->name());19301931// iterate over the operand list1932for( expand_instr->reset(); (opid = expand_instr->iter()) != NULL; ) {1933fprintf(fp,"%s ", opid);1934}1935fprintf(fp,");\n");1936}1937}19381939//------------------------------RewriteRule------------------------------------1940RewriteRule::RewriteRule(char* params, char* block)1941: _tempParams(params), _tempBlock(block) { }; // Constructor1942RewriteRule::~RewriteRule() { // Destructor1943}19441945void RewriteRule::dump() {1946output(stderr);1947}19481949void RewriteRule::output(FILE *fp) { // Write info to output files1950fprintf(fp,"\nRewrite Rule:\n%s\n%s\n",1951(_tempParams?_tempParams:""),1952(_tempBlock?_tempBlock:""));1953}195419551956//==============================MachNodes======================================1957//------------------------------MachNodeForm-----------------------------------1958MachNodeForm::MachNodeForm(char *id)1959: _ident(id) {1960}19611962MachNodeForm::~MachNodeForm() {1963}19641965MachNodeForm *MachNodeForm::is_machnode() const {1966return (MachNodeForm*)this;1967}19681969//==============================Operand Classes================================1970//------------------------------OpClassForm------------------------------------1971OpClassForm::OpClassForm(const char* id) : _ident(id) {1972_ftype = Form::OPCLASS;1973}19741975OpClassForm::~OpClassForm() {1976}19771978bool OpClassForm::ideal_only() const { return 0; }19791980OpClassForm *OpClassForm::is_opclass() const {1981return (OpClassForm*)this;1982}19831984Form::InterfaceType OpClassForm::interface_type(FormDict &globals) const {1985if( _oplst.count() == 0 ) return Form::no_interface;19861987// Check that my operands have the same interface type1988Form::InterfaceType interface;1989bool first = true;1990NameList &op_list = (NameList &)_oplst;1991op_list.reset();1992const char *op_name;1993while( (op_name = op_list.iter()) != NULL ) {1994const Form *form = globals[op_name];1995OperandForm *operand = form->is_operand();1996assert( operand, "Entry in operand class that is not an operand");1997if( first ) {1998first = false;1999interface = operand->interface_type(globals);2000} else {2001interface = (interface == operand->interface_type(globals) ? interface : Form::no_interface);2002}2003}2004return interface;2005}20062007bool OpClassForm::stack_slots_only(FormDict &globals) const {2008if( _oplst.count() == 0 ) return false; // how?20092010NameList &op_list = (NameList &)_oplst;2011op_list.reset();2012const char *op_name;2013while( (op_name = op_list.iter()) != NULL ) {2014const Form *form = globals[op_name];2015OperandForm *operand = form->is_operand();2016assert( operand, "Entry in operand class that is not an operand");2017if( !operand->stack_slots_only(globals) ) return false;2018}2019return true;2020}202120222023void OpClassForm::dump() {2024output(stderr);2025}20262027void OpClassForm::output(FILE *fp) {2028const char *name;2029fprintf(fp,"\nOperand Class: %s\n", (_ident?_ident:""));2030fprintf(fp,"\nCount = %d\n", _oplst.count());2031for(_oplst.reset(); (name = _oplst.iter()) != NULL;) {2032fprintf(fp,"%s, ",name);2033}2034fprintf(fp,"\n");2035}203620372038//==============================Operands=======================================2039//------------------------------OperandForm------------------------------------2040OperandForm::OperandForm(const char* id)2041: OpClassForm(id), _ideal_only(false),2042_localNames(cmpstr, hashstr, Form::arena) {2043_ftype = Form::OPER;20442045_matrule = NULL;2046_interface = NULL;2047_attribs = NULL;2048_predicate = NULL;2049_constraint= NULL;2050_construct = NULL;2051_format = NULL;2052}2053OperandForm::OperandForm(const char* id, bool ideal_only)2054: OpClassForm(id), _ideal_only(ideal_only),2055_localNames(cmpstr, hashstr, Form::arena) {2056_ftype = Form::OPER;20572058_matrule = NULL;2059_interface = NULL;2060_attribs = NULL;2061_predicate = NULL;2062_constraint= NULL;2063_construct = NULL;2064_format = NULL;2065}2066OperandForm::~OperandForm() {2067}206820692070OperandForm *OperandForm::is_operand() const {2071return (OperandForm*)this;2072}20732074bool OperandForm::ideal_only() const {2075return _ideal_only;2076}20772078Form::InterfaceType OperandForm::interface_type(FormDict &globals) const {2079if( _interface == NULL ) return Form::no_interface;20802081return _interface->interface_type(globals);2082}208320842085bool OperandForm::stack_slots_only(FormDict &globals) const {2086if( _constraint == NULL ) return false;2087return _constraint->stack_slots_only();2088}208920902091// Access op_cost attribute or return NULL.2092const char* OperandForm::cost() {2093for (Attribute* cur = _attribs; cur != NULL; cur = (Attribute*)cur->_next) {2094if( strcmp(cur->_ident,AttributeForm::_op_cost) == 0 ) {2095return cur->_val;2096}2097}2098return NULL;2099}21002101// Return the number of leaves below this complex operand2102uint OperandForm::num_leaves() const {2103if ( ! _matrule) return 0;21042105int num_leaves = _matrule->_numleaves;2106return num_leaves;2107}21082109// Return the number of constants contained within this complex operand2110uint OperandForm::num_consts(FormDict &globals) const {2111if ( ! _matrule) return 0;21122113// This is a recursive invocation on all operands in the matchrule2114return _matrule->num_consts(globals);2115}21162117// Return the number of constants in match rule with specified type2118uint OperandForm::num_consts(FormDict &globals, Form::DataType type) const {2119if ( ! _matrule) return 0;21202121// This is a recursive invocation on all operands in the matchrule2122return _matrule->num_consts(globals, type);2123}21242125// Return the number of pointer constants contained within this complex operand2126uint OperandForm::num_const_ptrs(FormDict &globals) const {2127if ( ! _matrule) return 0;21282129// This is a recursive invocation on all operands in the matchrule2130return _matrule->num_const_ptrs(globals);2131}21322133uint OperandForm::num_edges(FormDict &globals) const {2134uint edges = 0;2135uint leaves = num_leaves();2136uint consts = num_consts(globals);21372138// If we are matching a constant directly, there are no leaves.2139edges = ( leaves > consts ) ? leaves - consts : 0;21402141// !!!!!2142// Special case operands that do not have a corresponding ideal node.2143if( (edges == 0) && (consts == 0) ) {2144if( constrained_reg_class() != NULL ) {2145edges = 1;2146} else {2147if( _matrule2148&& (_matrule->_lChild == NULL) && (_matrule->_rChild == NULL) ) {2149const Form *form = globals[_matrule->_opType];2150OperandForm *oper = form ? form->is_operand() : NULL;2151if( oper ) {2152return oper->num_edges(globals);2153}2154}2155}2156}21572158return edges;2159}216021612162// Check if this operand is usable for cisc-spilling2163bool OperandForm::is_cisc_reg(FormDict &globals) const {2164const char *ideal = ideal_type(globals);2165bool is_cisc_reg = (ideal && (ideal_to_Reg_type(ideal) != none));2166return is_cisc_reg;2167}21682169bool OpClassForm::is_cisc_mem(FormDict &globals) const {2170Form::InterfaceType my_interface = interface_type(globals);2171return (my_interface == memory_interface);2172}217321742175// node matches ideal 'Bool'2176bool OperandForm::is_ideal_bool() const {2177if( _matrule == NULL ) return false;21782179return _matrule->is_ideal_bool();2180}21812182// Require user's name for an sRegX to be stackSlotX2183Form::DataType OperandForm::is_user_name_for_sReg() const {2184DataType data_type = none;2185if( _ident != NULL ) {2186if( strcmp(_ident,"stackSlotI") == 0 ) data_type = Form::idealI;2187else if( strcmp(_ident,"stackSlotP") == 0 ) data_type = Form::idealP;2188else if( strcmp(_ident,"stackSlotD") == 0 ) data_type = Form::idealD;2189else if( strcmp(_ident,"stackSlotF") == 0 ) data_type = Form::idealF;2190else if( strcmp(_ident,"stackSlotL") == 0 ) data_type = Form::idealL;2191}2192assert((data_type == none) || (_matrule == NULL), "No match-rule for stackSlotX");21932194return data_type;2195}219621972198// Return ideal type, if there is a single ideal type for this operand2199const char *OperandForm::ideal_type(FormDict &globals, RegisterForm *registers) const {2200const char *type = NULL;2201if (ideal_only()) type = _ident;2202else if( _matrule == NULL ) {2203// Check for condition code register2204const char *rc_name = constrained_reg_class();2205// !!!!!2206if (rc_name == NULL) return NULL;2207// !!!!! !!!!!2208// Check constraints on result's register class2209if( registers ) {2210RegClass *reg_class = registers->getRegClass(rc_name);2211assert( reg_class != NULL, "Register class is not defined");22122213// Check for ideal type of entries in register class, all are the same type2214reg_class->reset();2215RegDef *reg_def = reg_class->RegDef_iter();2216assert( reg_def != NULL, "No entries in register class");2217assert( reg_def->_idealtype != NULL, "Did not define ideal type for register");2218// Return substring that names the register's ideal type2219type = reg_def->_idealtype + 3;2220assert( *(reg_def->_idealtype + 0) == 'O', "Expect Op_ prefix");2221assert( *(reg_def->_idealtype + 1) == 'p', "Expect Op_ prefix");2222assert( *(reg_def->_idealtype + 2) == '_', "Expect Op_ prefix");2223}2224}2225else if( _matrule->_lChild == NULL && _matrule->_rChild == NULL ) {2226// This operand matches a single type, at the top level.2227// Check for ideal type2228type = _matrule->_opType;2229if( strcmp(type,"Bool") == 0 )2230return "Bool";2231// transitive lookup2232const Form *frm = globals[type];2233OperandForm *op = frm->is_operand();2234type = op->ideal_type(globals, registers);2235}2236return type;2237}223822392240// If there is a single ideal type for this interface field, return it.2241const char *OperandForm::interface_ideal_type(FormDict &globals,2242const char *field) const {2243const char *ideal_type = NULL;2244const char *value = NULL;22452246// Check if "field" is valid for this operand's interface2247if ( ! is_interface_field(field, value) ) return ideal_type;22482249// !!!!! !!!!! !!!!!2250// If a valid field has a constant value, identify "ConI" or "ConP" or ...22512252// Else, lookup type of field's replacement variable22532254return ideal_type;2255}225622572258RegClass* OperandForm::get_RegClass() const {2259if (_interface && !_interface->is_RegInterface()) return NULL;2260return globalAD->get_registers()->getRegClass(constrained_reg_class());2261}226222632264bool OperandForm::is_bound_register() const {2265RegClass* reg_class = get_RegClass();2266if (reg_class == NULL) {2267return false;2268}22692270const char* name = ideal_type(globalAD->globalNames());2271if (name == NULL) {2272return false;2273}22742275uint size = 0;2276if (strcmp(name, "RegFlags") == 0) size = 1;2277if (strcmp(name, "RegI") == 0) size = 1;2278if (strcmp(name, "RegF") == 0) size = 1;2279if (strcmp(name, "RegD") == 0) size = 2;2280if (strcmp(name, "RegL") == 0) size = 2;2281if (strcmp(name, "RegN") == 0) size = 1;2282if (strcmp(name, "VecX") == 0) size = 4;2283if (strcmp(name, "VecY") == 0) size = 8;2284if (strcmp(name, "VecZ") == 0) size = 16;2285if (strcmp(name, "RegP") == 0) size = globalAD->get_preproc_def("_LP64") ? 2 : 1;2286if (size == 0) {2287return false;2288}2289return size == reg_class->size();2290}229122922293// Check if this is a valid field for this operand,2294// Return 'true' if valid, and set the value to the string the user provided.2295bool OperandForm::is_interface_field(const char *field,2296const char * &value) const {2297return false;2298}229923002301// Return register class name if a constraint specifies the register class.2302const char *OperandForm::constrained_reg_class() const {2303const char *reg_class = NULL;2304if ( _constraint ) {2305// !!!!!2306Constraint *constraint = _constraint;2307if ( strcmp(_constraint->_func,"ALLOC_IN_RC") == 0 ) {2308reg_class = _constraint->_arg;2309}2310}23112312return reg_class;2313}231423152316// Return the register class associated with 'leaf'.2317const char *OperandForm::in_reg_class(uint leaf, FormDict &globals) {2318const char *reg_class = NULL; // "RegMask::Empty";23192320if((_matrule == NULL) || (_matrule->is_chain_rule(globals))) {2321reg_class = constrained_reg_class();2322return reg_class;2323}2324const char *result = NULL;2325const char *name = NULL;2326const char *type = NULL;2327// iterate through all base operands2328// until we reach the register that corresponds to "leaf"2329// This function is not looking for an ideal type. It needs the first2330// level user type associated with the leaf.2331for(uint idx = 0;_matrule->base_operand(idx,globals,result,name,type);++idx) {2332const Form *form = (_localNames[name] ? _localNames[name] : globals[result]);2333OperandForm *oper = form ? form->is_operand() : NULL;2334if( oper ) {2335reg_class = oper->constrained_reg_class();2336if( reg_class ) {2337reg_class = reg_class;2338} else {2339// ShouldNotReachHere();2340}2341} else {2342// ShouldNotReachHere();2343}23442345// Increment our target leaf position if current leaf is not a candidate.2346if( reg_class == NULL) ++leaf;2347// Exit the loop with the value of reg_class when at the correct index2348if( idx == leaf ) break;2349// May iterate through all base operands if reg_class for 'leaf' is NULL2350}2351return reg_class;2352}235323542355// Recursive call to construct list of top-level operands.2356// Implementation does not modify state of internal structures2357void OperandForm::build_components() {2358if (_matrule) _matrule->append_components(_localNames, _components);23592360// Add parameters that "do not appear in match rule".2361const char *name;2362for (_parameters.reset(); (name = _parameters.iter()) != NULL;) {2363OpClassForm *opForm = _localNames[name]->is_opclass();2364assert(opForm != NULL, "sanity");23652366if ( _components.operand_position(name) == -1 ) {2367_components.insert(name, opForm->_ident, Component::INVALID, false);2368}2369}23702371return;2372}23732374int OperandForm::operand_position(const char *name, int usedef) {2375return _components.operand_position(name, usedef, this);2376}237723782379// Return zero-based position in component list, only counting constants;2380// Return -1 if not in list.2381int OperandForm::constant_position(FormDict &globals, const Component *last) {2382// Iterate through components and count constants preceding 'constant'2383int position = 0;2384Component *comp;2385_components.reset();2386while( (comp = _components.iter()) != NULL && (comp != last) ) {2387// Special case for operands that take a single user-defined operand2388// Skip the initial definition in the component list.2389if( strcmp(comp->_name,this->_ident) == 0 ) continue;23902391const char *type = comp->_type;2392// Lookup operand form for replacement variable's type2393const Form *form = globals[type];2394assert( form != NULL, "Component's type not found");2395OperandForm *oper = form ? form->is_operand() : NULL;2396if( oper ) {2397if( oper->_matrule->is_base_constant(globals) != Form::none ) {2398++position;2399}2400}2401}24022403// Check for being passed a component that was not in the list2404if( comp != last ) position = -1;24052406return position;2407}2408// Provide position of constant by "name"2409int OperandForm::constant_position(FormDict &globals, const char *name) {2410const Component *comp = _components.search(name);2411int idx = constant_position( globals, comp );24122413return idx;2414}241524162417// Return zero-based position in component list, only counting constants;2418// Return -1 if not in list.2419int OperandForm::register_position(FormDict &globals, const char *reg_name) {2420// Iterate through components and count registers preceding 'last'2421uint position = 0;2422Component *comp;2423_components.reset();2424while( (comp = _components.iter()) != NULL2425&& (strcmp(comp->_name,reg_name) != 0) ) {2426// Special case for operands that take a single user-defined operand2427// Skip the initial definition in the component list.2428if( strcmp(comp->_name,this->_ident) == 0 ) continue;24292430const char *type = comp->_type;2431// Lookup operand form for component's type2432const Form *form = globals[type];2433assert( form != NULL, "Component's type not found");2434OperandForm *oper = form ? form->is_operand() : NULL;2435if( oper ) {2436if( oper->_matrule->is_base_register(globals) ) {2437++position;2438}2439}2440}24412442return position;2443}244424452446const char *OperandForm::reduce_result() const {2447return _ident;2448}2449// Return the name of the operand on the right hand side of the binary match2450// Return NULL if there is no right hand side2451const char *OperandForm::reduce_right(FormDict &globals) const {2452return ( _matrule ? _matrule->reduce_right(globals) : NULL );2453}24542455// Similar for left2456const char *OperandForm::reduce_left(FormDict &globals) const {2457return ( _matrule ? _matrule->reduce_left(globals) : NULL );2458}245924602461// --------------------------- FILE *output_routines2462//2463// Output code for disp_is_oop, if true.2464void OperandForm::disp_is_oop(FILE *fp, FormDict &globals) {2465// Check it is a memory interface with a non-user-constant disp field2466if ( this->_interface == NULL ) return;2467MemInterface *mem_interface = this->_interface->is_MemInterface();2468if ( mem_interface == NULL ) return;2469const char *disp = mem_interface->_disp;2470if ( *disp != '$' ) return;24712472// Lookup replacement variable in operand's component list2473const char *rep_var = disp + 1;2474const Component *comp = this->_components.search(rep_var);2475assert( comp != NULL, "Replacement variable not found in components");2476// Lookup operand form for replacement variable's type2477const char *type = comp->_type;2478Form *form = (Form*)globals[type];2479assert( form != NULL, "Replacement variable's type not found");2480OperandForm *op = form->is_operand();2481assert( op, "Memory Interface 'disp' can only emit an operand form");2482// Check if this is a ConP, which may require relocation2483if ( op->is_base_constant(globals) == Form::idealP ) {2484// Find the constant's index: _c0, _c1, _c2, ... , _cN2485uint idx = op->constant_position( globals, rep_var);2486fprintf(fp," virtual relocInfo::relocType disp_reloc() const {");2487fprintf(fp, " return _c%d->reloc();", idx);2488fprintf(fp, " }\n");2489}2490}24912492// Generate code for internal and external format methods2493//2494// internal access to reg# node->_idx2495// access to subsumed constant _c0, _c1,2496void OperandForm::int_format(FILE *fp, FormDict &globals, uint index) {2497Form::DataType dtype;2498if (_matrule && (_matrule->is_base_register(globals) ||2499strcmp(ideal_type(globalAD->globalNames()), "RegFlags") == 0)) {2500// !!!!! !!!!!2501fprintf(fp," { char reg_str[128];\n");2502fprintf(fp," ra->dump_register(node,reg_str);\n");2503fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2504fprintf(fp," }\n");2505} else if (_matrule && (dtype = _matrule->is_base_constant(globals)) != Form::none) {2506format_constant( fp, index, dtype );2507} else if (ideal_to_sReg_type(_ident) != Form::none) {2508// Special format for Stack Slot Register2509fprintf(fp," { char reg_str[128];\n");2510fprintf(fp," ra->dump_register(node,reg_str);\n");2511fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2512fprintf(fp," }\n");2513} else {2514fprintf(fp," st->print(\"No format defined for %s\n\");\n", _ident);2515fflush(fp);2516fprintf(stderr,"No format defined for %s\n", _ident);2517dump();2518assert( false,"Internal error:\n output_internal_operand() attempting to output other than a Register or Constant");2519}2520}25212522// Similar to "int_format" but for cases where data is external to operand2523// external access to reg# node->in(idx)->_idx,2524void OperandForm::ext_format(FILE *fp, FormDict &globals, uint index) {2525Form::DataType dtype;2526if (_matrule && (_matrule->is_base_register(globals) ||2527strcmp(ideal_type(globalAD->globalNames()), "RegFlags") == 0)) {2528fprintf(fp," { char reg_str[128];\n");2529fprintf(fp," ra->dump_register(node->in(idx");2530if ( index != 0 ) fprintf(fp, "+%d",index);2531fprintf(fp, "),reg_str);\n");2532fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2533fprintf(fp," }\n");2534} else if (_matrule && (dtype = _matrule->is_base_constant(globals)) != Form::none) {2535format_constant( fp, index, dtype );2536} else if (ideal_to_sReg_type(_ident) != Form::none) {2537// Special format for Stack Slot Register2538fprintf(fp," { char reg_str[128];\n");2539fprintf(fp," ra->dump_register(node->in(idx");2540if ( index != 0 ) fprintf(fp, "+%d",index);2541fprintf(fp, "),reg_str);\n");2542fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2543fprintf(fp," }\n");2544} else {2545fprintf(fp," st->print(\"No format defined for %s\n\");\n", _ident);2546assert( false,"Internal error:\n output_external_operand() attempting to output other than a Register or Constant");2547}2548}25492550void OperandForm::format_constant(FILE *fp, uint const_index, uint const_type) {2551switch(const_type) {2552case Form::idealI: fprintf(fp," st->print(\"#%%d\", _c%d);\n", const_index); break;2553case Form::idealP: fprintf(fp," if (_c%d) _c%d->dump_on(st);\n", const_index, const_index); break;2554case Form::idealNKlass:2555case Form::idealN: fprintf(fp," if (_c%d) _c%d->dump_on(st);\n", const_index, const_index); break;2556case Form::idealL: fprintf(fp," st->print(\"#\" INT64_FORMAT, (int64_t)_c%d);\n", const_index); break;2557case Form::idealF: fprintf(fp," st->print(\"#%%f\", _c%d);\n", const_index); break;2558case Form::idealD: fprintf(fp," st->print(\"#%%f\", _c%d);\n", const_index); break;2559default:2560assert( false, "ShouldNotReachHere()");2561}2562}25632564// Return the operand form corresponding to the given index, else NULL.2565OperandForm *OperandForm::constant_operand(FormDict &globals,2566uint index) {2567// !!!!!2568// Check behavior on complex operands2569uint n_consts = num_consts(globals);2570if( n_consts > 0 ) {2571uint i = 0;2572const char *type;2573Component *comp;2574_components.reset();2575if ((comp = _components.iter()) == NULL) {2576assert(n_consts == 1, "Bad component list detected.\n");2577// Current operand is THE operand2578if ( index == 0 ) {2579return this;2580}2581} // end if NULL2582else {2583// Skip the first component, it can not be a DEF of a constant2584do {2585type = comp->base_type(globals);2586// Check that "type" is a 'ConI', 'ConP', ...2587if ( ideal_to_const_type(type) != Form::none ) {2588// When at correct component, get corresponding Operand2589if ( index == 0 ) {2590return globals[comp->_type]->is_operand();2591}2592// Decrement number of constants to go2593--index;2594}2595} while((comp = _components.iter()) != NULL);2596}2597}25982599// Did not find a constant for this index.2600return NULL;2601}26022603// If this operand has a single ideal type, return its type2604Form::DataType OperandForm::simple_type(FormDict &globals) const {2605const char *type_name = ideal_type(globals);2606Form::DataType type = type_name ? ideal_to_const_type( type_name )2607: Form::none;2608return type;2609}26102611Form::DataType OperandForm::is_base_constant(FormDict &globals) const {2612if ( _matrule == NULL ) return Form::none;26132614return _matrule->is_base_constant(globals);2615}26162617// "true" if this operand is a simple type that is swallowed2618bool OperandForm::swallowed(FormDict &globals) const {2619Form::DataType type = simple_type(globals);2620if( type != Form::none ) {2621return true;2622}26232624return false;2625}26262627// Output code to access the value of the index'th constant2628void OperandForm::access_constant(FILE *fp, FormDict &globals,2629uint const_index) {2630OperandForm *oper = constant_operand(globals, const_index);2631assert( oper, "Index exceeds number of constants in operand");2632Form::DataType dtype = oper->is_base_constant(globals);26332634switch(dtype) {2635case idealI: fprintf(fp,"_c%d", const_index); break;2636case idealP: fprintf(fp,"_c%d->get_con()",const_index); break;2637case idealL: fprintf(fp,"_c%d", const_index); break;2638case idealF: fprintf(fp,"_c%d", const_index); break;2639case idealD: fprintf(fp,"_c%d", const_index); break;2640default:2641assert( false, "ShouldNotReachHere()");2642}2643}264426452646void OperandForm::dump() {2647output(stderr);2648}26492650void OperandForm::output(FILE *fp) {2651fprintf(fp,"\nOperand: %s\n", (_ident?_ident:""));2652if (_matrule) _matrule->dump();2653if (_interface) _interface->dump();2654if (_attribs) _attribs->dump();2655if (_predicate) _predicate->dump();2656if (_constraint) _constraint->dump();2657if (_construct) _construct->dump();2658if (_format) _format->dump();2659}26602661//------------------------------Constraint-------------------------------------2662Constraint::Constraint(const char *func, const char *arg)2663: _func(func), _arg(arg) {2664}2665Constraint::~Constraint() { /* not owner of char* */2666}26672668bool Constraint::stack_slots_only() const {2669return strcmp(_func, "ALLOC_IN_RC") == 02670&& strcmp(_arg, "stack_slots") == 0;2671}26722673void Constraint::dump() {2674output(stderr);2675}26762677void Constraint::output(FILE *fp) { // Write info to output files2678assert((_func != NULL && _arg != NULL),"missing constraint function or arg");2679fprintf(fp,"Constraint: %s ( %s )\n", _func, _arg);2680}26812682//------------------------------Predicate--------------------------------------2683Predicate::Predicate(char *pr)2684: _pred(pr) {2685}2686Predicate::~Predicate() {2687}26882689void Predicate::dump() {2690output(stderr);2691}26922693void Predicate::output(FILE *fp) {2694fprintf(fp,"Predicate"); // Write to output files2695}2696//------------------------------Interface--------------------------------------2697Interface::Interface(const char *name) : _name(name) {2698}2699Interface::~Interface() {2700}27012702Form::InterfaceType Interface::interface_type(FormDict &globals) const {2703Interface *thsi = (Interface*)this;2704if ( thsi->is_RegInterface() ) return Form::register_interface;2705if ( thsi->is_MemInterface() ) return Form::memory_interface;2706if ( thsi->is_ConstInterface() ) return Form::constant_interface;2707if ( thsi->is_CondInterface() ) return Form::conditional_interface;27082709return Form::no_interface;2710}27112712RegInterface *Interface::is_RegInterface() {2713if ( strcmp(_name,"REG_INTER") != 0 )2714return NULL;2715return (RegInterface*)this;2716}2717MemInterface *Interface::is_MemInterface() {2718if ( strcmp(_name,"MEMORY_INTER") != 0 ) return NULL;2719return (MemInterface*)this;2720}2721ConstInterface *Interface::is_ConstInterface() {2722if ( strcmp(_name,"CONST_INTER") != 0 ) return NULL;2723return (ConstInterface*)this;2724}2725CondInterface *Interface::is_CondInterface() {2726if ( strcmp(_name,"COND_INTER") != 0 ) return NULL;2727return (CondInterface*)this;2728}272927302731void Interface::dump() {2732output(stderr);2733}27342735// Write info to output files2736void Interface::output(FILE *fp) {2737fprintf(fp,"Interface: %s\n", (_name ? _name : "") );2738}27392740//------------------------------RegInterface-----------------------------------2741RegInterface::RegInterface() : Interface("REG_INTER") {2742}2743RegInterface::~RegInterface() {2744}27452746void RegInterface::dump() {2747output(stderr);2748}27492750// Write info to output files2751void RegInterface::output(FILE *fp) {2752Interface::output(fp);2753}27542755//------------------------------ConstInterface---------------------------------2756ConstInterface::ConstInterface() : Interface("CONST_INTER") {2757}2758ConstInterface::~ConstInterface() {2759}27602761void ConstInterface::dump() {2762output(stderr);2763}27642765// Write info to output files2766void ConstInterface::output(FILE *fp) {2767Interface::output(fp);2768}27692770//------------------------------MemInterface-----------------------------------2771MemInterface::MemInterface(char *base, char *index, char *scale, char *disp)2772: Interface("MEMORY_INTER"), _base(base), _index(index), _scale(scale), _disp(disp) {2773}2774MemInterface::~MemInterface() {2775// not owner of any character arrays2776}27772778void MemInterface::dump() {2779output(stderr);2780}27812782// Write info to output files2783void MemInterface::output(FILE *fp) {2784Interface::output(fp);2785if ( _base != NULL ) fprintf(fp," base == %s\n", _base);2786if ( _index != NULL ) fprintf(fp," index == %s\n", _index);2787if ( _scale != NULL ) fprintf(fp," scale == %s\n", _scale);2788if ( _disp != NULL ) fprintf(fp," disp == %s\n", _disp);2789// fprintf(fp,"\n");2790}27912792//------------------------------CondInterface----------------------------------2793CondInterface::CondInterface(const char* equal, const char* equal_format,2794const char* not_equal, const char* not_equal_format,2795const char* less, const char* less_format,2796const char* greater_equal, const char* greater_equal_format,2797const char* less_equal, const char* less_equal_format,2798const char* greater, const char* greater_format,2799const char* overflow, const char* overflow_format,2800const char* no_overflow, const char* no_overflow_format)2801: Interface("COND_INTER"),2802_equal(equal), _equal_format(equal_format),2803_not_equal(not_equal), _not_equal_format(not_equal_format),2804_less(less), _less_format(less_format),2805_greater_equal(greater_equal), _greater_equal_format(greater_equal_format),2806_less_equal(less_equal), _less_equal_format(less_equal_format),2807_greater(greater), _greater_format(greater_format),2808_overflow(overflow), _overflow_format(overflow_format),2809_no_overflow(no_overflow), _no_overflow_format(no_overflow_format) {2810}2811CondInterface::~CondInterface() {2812// not owner of any character arrays2813}28142815void CondInterface::dump() {2816output(stderr);2817}28182819// Write info to output files2820void CondInterface::output(FILE *fp) {2821Interface::output(fp);2822if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal);2823if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal);2824if ( _less != NULL ) fprintf(fp," less == %s\n", _less);2825if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal);2826if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal);2827if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater);2828if ( _overflow != NULL ) fprintf(fp," overflow == %s\n", _overflow);2829if ( _no_overflow != NULL ) fprintf(fp," no_overflow == %s\n", _no_overflow);2830// fprintf(fp,"\n");2831}28322833//------------------------------ConstructRule----------------------------------2834ConstructRule::ConstructRule(char *cnstr)2835: _construct(cnstr) {2836}2837ConstructRule::~ConstructRule() {2838}28392840void ConstructRule::dump() {2841output(stderr);2842}28432844void ConstructRule::output(FILE *fp) {2845fprintf(fp,"\nConstruct Rule\n"); // Write to output files2846}284728482849//==============================Shared Forms===================================2850//------------------------------AttributeForm----------------------------------2851int AttributeForm::_insId = 0; // start counter at 02852int AttributeForm::_opId = 0; // start counter at 02853const char* AttributeForm::_ins_cost = "ins_cost"; // required name2854const char* AttributeForm::_op_cost = "op_cost"; // required name28552856AttributeForm::AttributeForm(char *attr, int type, char *attrdef)2857: Form(Form::ATTR), _attrname(attr), _atype(type), _attrdef(attrdef) {2858if (type==OP_ATTR) {2859id = ++_opId;2860}2861else if (type==INS_ATTR) {2862id = ++_insId;2863}2864else assert( false,"");2865}2866AttributeForm::~AttributeForm() {2867}28682869// Dynamic type check2870AttributeForm *AttributeForm::is_attribute() const {2871return (AttributeForm*)this;2872}287328742875// inlined // int AttributeForm::type() { return id;}28762877void AttributeForm::dump() {2878output(stderr);2879}28802881void AttributeForm::output(FILE *fp) {2882if( _attrname && _attrdef ) {2883fprintf(fp,"\n// AttributeForm \nstatic const int %s = %s;\n",2884_attrname, _attrdef);2885}2886else {2887fprintf(fp,"\n// AttributeForm missing name %s or definition %s\n",2888(_attrname?_attrname:""), (_attrdef?_attrdef:"") );2889}2890}28912892//------------------------------Component--------------------------------------2893Component::Component(const char *name, const char *type, int usedef)2894: _name(name), _type(type), _usedef(usedef) {2895_ftype = Form::COMP;2896}2897Component::~Component() {2898}28992900// True if this component is equal to the parameter.2901bool Component::is(int use_def_kill_enum) const {2902return (_usedef == use_def_kill_enum ? true : false);2903}2904// True if this component is used/def'd/kill'd as the parameter suggests.2905bool Component::isa(int use_def_kill_enum) const {2906return (_usedef & use_def_kill_enum) == use_def_kill_enum;2907}29082909// Extend this component with additional use/def/kill behavior2910int Component::promote_use_def_info(int new_use_def) {2911_usedef |= new_use_def;29122913return _usedef;2914}29152916// Check the base type of this component, if it has one2917const char *Component::base_type(FormDict &globals) {2918const Form *frm = globals[_type];2919if (frm == NULL) return NULL;2920OperandForm *op = frm->is_operand();2921if (op == NULL) return NULL;2922if (op->ideal_only()) return op->_ident;2923return (char *)op->ideal_type(globals);2924}29252926void Component::dump() {2927output(stderr);2928}29292930void Component::output(FILE *fp) {2931fprintf(fp,"Component:"); // Write to output files2932fprintf(fp, " name = %s", _name);2933fprintf(fp, ", type = %s", _type);2934assert(_usedef != 0, "unknown effect");2935fprintf(fp, ", use/def = %s\n", getUsedefName());2936}293729382939//------------------------------ComponentList---------------------------------2940ComponentList::ComponentList() : NameList(), _matchcnt(0) {2941}2942ComponentList::~ComponentList() {2943// // This list may not own its elements if copied via assignment2944// Component *component;2945// for (reset(); (component = iter()) != NULL;) {2946// delete component;2947// }2948}29492950void ComponentList::insert(Component *component, bool mflag) {2951NameList::addName((char *)component);2952if(mflag) _matchcnt++;2953}2954void ComponentList::insert(const char *name, const char *opType, int usedef,2955bool mflag) {2956Component * component = new Component(name, opType, usedef);2957insert(component, mflag);2958}2959Component *ComponentList::current() { return (Component*)NameList::current(); }2960Component *ComponentList::iter() { return (Component*)NameList::iter(); }2961Component *ComponentList::match_iter() {2962if(_iter < _matchcnt) return (Component*)NameList::iter();2963return NULL;2964}2965Component *ComponentList::post_match_iter() {2966Component *comp = iter();2967// At end of list?2968if ( comp == NULL ) {2969return comp;2970}2971// In post-match components?2972if (_iter > match_count()-1) {2973return comp;2974}29752976return post_match_iter();2977}29782979void ComponentList::reset() { NameList::reset(); }2980int ComponentList::count() { return NameList::count(); }29812982Component *ComponentList::operator[](int position) {2983// Shortcut complete iteration if there are not enough entries2984if (position >= count()) return NULL;29852986int index = 0;2987Component *component = NULL;2988for (reset(); (component = iter()) != NULL;) {2989if (index == position) {2990return component;2991}2992++index;2993}29942995return NULL;2996}29972998const Component *ComponentList::search(const char *name) {2999PreserveIter pi(this);3000reset();3001for( Component *comp = NULL; ((comp = iter()) != NULL); ) {3002if( strcmp(comp->_name,name) == 0 ) return comp;3003}30043005return NULL;3006}30073008// Return number of USEs + number of DEFs3009// When there are no components, or the first component is a USE,3010// then we add '1' to hold a space for the 'result' operand.3011int ComponentList::num_operands() {3012PreserveIter pi(this);3013uint count = 1; // result operand3014uint position = 0;30153016Component *component = NULL;3017for( reset(); (component = iter()) != NULL; ++position ) {3018if( component->isa(Component::USE) ||3019( position == 0 && (! component->isa(Component::DEF))) ) {3020++count;3021}3022}30233024return count;3025}30263027// Return zero-based position of operand 'name' in list; -1 if not in list.3028// if parameter 'usedef' is ::USE, it will match USE, USE_DEF, ...3029int ComponentList::operand_position(const char *name, int usedef, Form *fm) {3030PreserveIter pi(this);3031int position = 0;3032int num_opnds = num_operands();3033Component *component;3034Component* preceding_non_use = NULL;3035Component* first_def = NULL;3036for (reset(); (component = iter()) != NULL; ++position) {3037// When the first component is not a DEF,3038// leave space for the result operand!3039if ( position==0 && (! component->isa(Component::DEF)) ) {3040++position;3041++num_opnds;3042}3043if (strcmp(name, component->_name)==0 && (component->isa(usedef))) {3044// When the first entry in the component list is a DEF and a USE3045// Treat them as being separate, a DEF first, then a USE3046if( position==03047&& usedef==Component::USE && component->isa(Component::DEF) ) {3048assert(position+1 < num_opnds, "advertised index in bounds");3049return position+1;3050} else {3051if( preceding_non_use && strcmp(component->_name, preceding_non_use->_name) ) {3052fprintf(stderr, "the name '%s(%s)' should not precede the name '%s(%s)'",3053preceding_non_use->_name, preceding_non_use->getUsedefName(),3054name, component->getUsedefName());3055if (fm && fm->is_instruction()) fprintf(stderr, "in form '%s'", fm->is_instruction()->_ident);3056if (fm && fm->is_operand()) fprintf(stderr, "in form '%s'", fm->is_operand()->_ident);3057fprintf(stderr, "\n");3058}3059if( position >= num_opnds ) {3060fprintf(stderr, "the name '%s' is too late in its name list", name);3061if (fm && fm->is_instruction()) fprintf(stderr, "in form '%s'", fm->is_instruction()->_ident);3062if (fm && fm->is_operand()) fprintf(stderr, "in form '%s'", fm->is_operand()->_ident);3063fprintf(stderr, "\n");3064}3065assert(position < num_opnds, "advertised index in bounds");3066return position;3067}3068}3069if( component->isa(Component::DEF)3070&& component->isa(Component::USE) ) {3071++position;3072if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3073}3074if( component->isa(Component::DEF) && !first_def ) {3075first_def = component;3076}3077if( !component->isa(Component::USE) && component != first_def ) {3078preceding_non_use = component;3079} else if( preceding_non_use && !strcmp(component->_name, preceding_non_use->_name) ) {3080preceding_non_use = NULL;3081}3082}3083return Not_in_list;3084}30853086// Find position for this name, regardless of use/def information3087int ComponentList::operand_position(const char *name) {3088PreserveIter pi(this);3089int position = 0;3090Component *component;3091for (reset(); (component = iter()) != NULL; ++position) {3092// When the first component is not a DEF,3093// leave space for the result operand!3094if ( position==0 && (! component->isa(Component::DEF)) ) {3095++position;3096}3097if (strcmp(name, component->_name)==0) {3098return position;3099}3100if( component->isa(Component::DEF)3101&& component->isa(Component::USE) ) {3102++position;3103if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3104}3105}3106return Not_in_list;3107}31083109int ComponentList::operand_position_format(const char *name, Form *fm) {3110PreserveIter pi(this);3111int first_position = operand_position(name);3112int use_position = operand_position(name, Component::USE, fm);31133114return ((first_position < use_position) ? use_position : first_position);3115}31163117int ComponentList::label_position() {3118PreserveIter pi(this);3119int position = 0;3120reset();3121for( Component *comp; (comp = iter()) != NULL; ++position) {3122// When the first component is not a DEF,3123// leave space for the result operand!3124if ( position==0 && (! comp->isa(Component::DEF)) ) {3125++position;3126}3127if (strcmp(comp->_type, "label")==0) {3128return position;3129}3130if( comp->isa(Component::DEF)3131&& comp->isa(Component::USE) ) {3132++position;3133if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3134}3135}31363137return -1;3138}31393140int ComponentList::method_position() {3141PreserveIter pi(this);3142int position = 0;3143reset();3144for( Component *comp; (comp = iter()) != NULL; ++position) {3145// When the first component is not a DEF,3146// leave space for the result operand!3147if ( position==0 && (! comp->isa(Component::DEF)) ) {3148++position;3149}3150if (strcmp(comp->_type, "method")==0) {3151return position;3152}3153if( comp->isa(Component::DEF)3154&& comp->isa(Component::USE) ) {3155++position;3156if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3157}3158}31593160return -1;3161}31623163void ComponentList::dump() { output(stderr); }31643165void ComponentList::output(FILE *fp) {3166PreserveIter pi(this);3167fprintf(fp, "\n");3168Component *component;3169for (reset(); (component = iter()) != NULL;) {3170component->output(fp);3171}3172fprintf(fp, "\n");3173}31743175//------------------------------MatchNode--------------------------------------3176MatchNode::MatchNode(ArchDesc &ad, const char *result, const char *mexpr,3177const char *opType, MatchNode *lChild, MatchNode *rChild)3178: _AD(ad), _result(result), _name(mexpr), _opType(opType),3179_lChild(lChild), _rChild(rChild), _internalop(0), _numleaves(0),3180_commutative_id(0) {3181_numleaves = (lChild ? lChild->_numleaves : 0)3182+ (rChild ? rChild->_numleaves : 0);3183}31843185MatchNode::MatchNode(ArchDesc &ad, MatchNode& mnode)3186: _AD(ad), _result(mnode._result), _name(mnode._name),3187_opType(mnode._opType), _lChild(mnode._lChild), _rChild(mnode._rChild),3188_internalop(0), _numleaves(mnode._numleaves),3189_commutative_id(mnode._commutative_id) {3190}31913192MatchNode::MatchNode(ArchDesc &ad, MatchNode& mnode, int clone)3193: _AD(ad), _result(mnode._result), _name(mnode._name),3194_opType(mnode._opType),3195_internalop(0), _numleaves(mnode._numleaves),3196_commutative_id(mnode._commutative_id) {3197if (mnode._lChild) {3198_lChild = new MatchNode(ad, *mnode._lChild, clone);3199} else {3200_lChild = NULL;3201}3202if (mnode._rChild) {3203_rChild = new MatchNode(ad, *mnode._rChild, clone);3204} else {3205_rChild = NULL;3206}3207}32083209MatchNode::~MatchNode() {3210// // This node may not own its children if copied via assignment3211// if( _lChild ) delete _lChild;3212// if( _rChild ) delete _rChild;3213}32143215bool MatchNode::find_type(const char *type, int &position) const {3216if ( (_lChild != NULL) && (_lChild->find_type(type, position)) ) return true;3217if ( (_rChild != NULL) && (_rChild->find_type(type, position)) ) return true;32183219if (strcmp(type,_opType)==0) {3220return true;3221} else {3222++position;3223}3224return false;3225}32263227// Recursive call collecting info on top-level operands, not transitive.3228// Implementation does not modify state of internal structures.3229void MatchNode::append_components(FormDict& locals, ComponentList& components,3230bool def_flag) const {3231int usedef = def_flag ? Component::DEF : Component::USE;3232FormDict &globals = _AD.globalNames();32333234assert (_name != NULL, "MatchNode::build_components encountered empty node\n");3235// Base case3236if (_lChild==NULL && _rChild==NULL) {3237// If _opType is not an operation, do not build a component for it #####3238const Form *f = globals[_opType];3239if( f != NULL ) {3240// Add non-ideals that are operands, operand-classes,3241if( ! f->ideal_only()3242&& (f->is_opclass() || f->is_operand()) ) {3243components.insert(_name, _opType, usedef, true);3244}3245}3246return;3247}3248// Promote results of "Set" to DEF3249bool tmpdef_flag = (!strcmp(_opType, "Set")) ? true : false;3250if (_lChild) _lChild->append_components(locals, components, tmpdef_flag);3251tmpdef_flag = false; // only applies to component immediately following 'Set'3252if (_rChild) _rChild->append_components(locals, components, tmpdef_flag);3253}32543255// Find the n'th base-operand in the match node,3256// recursively investigates match rules of user-defined operands.3257//3258// Implementation does not modify state of internal structures since they3259// can be shared.3260bool MatchNode::base_operand(uint &position, FormDict &globals,3261const char * &result, const char * &name,3262const char * &opType) const {3263assert (_name != NULL, "MatchNode::base_operand encountered empty node\n");3264// Base case3265if (_lChild==NULL && _rChild==NULL) {3266// Check for special case: "Universe", "label"3267if (strcmp(_opType,"Universe") == 0 || strcmp(_opType,"label")==0 ) {3268if (position == 0) {3269result = _result;3270name = _name;3271opType = _opType;3272return 1;3273} else {3274-- position;3275return 0;3276}3277}32783279const Form *form = globals[_opType];3280MatchNode *matchNode = NULL;3281// Check for user-defined type3282if (form) {3283// User operand or instruction?3284OperandForm *opForm = form->is_operand();3285InstructForm *inForm = form->is_instruction();3286if ( opForm ) {3287matchNode = (MatchNode*)opForm->_matrule;3288} else if ( inForm ) {3289matchNode = (MatchNode*)inForm->_matrule;3290}3291}3292// if this is user-defined, recurse on match rule3293// User-defined operand and instruction forms have a match-rule.3294if (matchNode) {3295return (matchNode->base_operand(position,globals,result,name,opType));3296} else {3297// Either not a form, or a system-defined form (no match rule).3298if (position==0) {3299result = _result;3300name = _name;3301opType = _opType;3302return 1;3303} else {3304--position;3305return 0;3306}3307}33083309} else {3310// Examine the left child and right child as well3311if (_lChild) {3312if (_lChild->base_operand(position, globals, result, name, opType))3313return 1;3314}33153316if (_rChild) {3317if (_rChild->base_operand(position, globals, result, name, opType))3318return 1;3319}3320}33213322return 0;3323}33243325// Recursive call on all operands' match rules in my match rule.3326uint MatchNode::num_consts(FormDict &globals) const {3327uint index = 0;3328uint num_consts = 0;3329const char *result;3330const char *name;3331const char *opType;33323333for (uint position = index;3334base_operand(position,globals,result,name,opType); position = index) {3335++index;3336if( ideal_to_const_type(opType) ) num_consts++;3337}33383339return num_consts;3340}33413342// Recursive call on all operands' match rules in my match rule.3343// Constants in match rule subtree with specified type3344uint MatchNode::num_consts(FormDict &globals, Form::DataType type) const {3345uint index = 0;3346uint num_consts = 0;3347const char *result;3348const char *name;3349const char *opType;33503351for (uint position = index;3352base_operand(position,globals,result,name,opType); position = index) {3353++index;3354if( ideal_to_const_type(opType) == type ) num_consts++;3355}33563357return num_consts;3358}33593360// Recursive call on all operands' match rules in my match rule.3361uint MatchNode::num_const_ptrs(FormDict &globals) const {3362return num_consts( globals, Form::idealP );3363}33643365bool MatchNode::sets_result() const {3366return ( (strcmp(_name,"Set") == 0) ? true : false );3367}33683369const char *MatchNode::reduce_right(FormDict &globals) const {3370// If there is no right reduction, return NULL.3371const char *rightStr = NULL;33723373// If we are a "Set", start from the right child.3374const MatchNode *const mnode = sets_result() ?3375(const MatchNode *)this->_rChild :3376(const MatchNode *)this;33773378// If our right child exists, it is the right reduction3379if ( mnode->_rChild ) {3380rightStr = mnode->_rChild->_internalop ? mnode->_rChild->_internalop3381: mnode->_rChild->_opType;3382}3383// Else, May be simple chain rule: (Set dst operand_form), rightStr=NULL;3384return rightStr;3385}33863387const char *MatchNode::reduce_left(FormDict &globals) const {3388// If there is no left reduction, return NULL.3389const char *leftStr = NULL;33903391// If we are a "Set", start from the right child.3392const MatchNode *const mnode = sets_result() ?3393(const MatchNode *)this->_rChild :3394(const MatchNode *)this;33953396// If our left child exists, it is the left reduction3397if ( mnode->_lChild ) {3398leftStr = mnode->_lChild->_internalop ? mnode->_lChild->_internalop3399: mnode->_lChild->_opType;3400} else {3401// May be simple chain rule: (Set dst operand_form_source)3402if ( sets_result() ) {3403OperandForm *oper = globals[mnode->_opType]->is_operand();3404if( oper ) {3405leftStr = mnode->_opType;3406}3407}3408}3409return leftStr;3410}34113412//------------------------------count_instr_names------------------------------3413// Count occurrences of operands names in the leaves of the instruction3414// match rule.3415void MatchNode::count_instr_names( Dict &names ) {3416if( _lChild ) _lChild->count_instr_names(names);3417if( _rChild ) _rChild->count_instr_names(names);3418if( !_lChild && !_rChild ) {3419uintptr_t cnt = (uintptr_t)names[_name];3420cnt++; // One more name found3421names.Insert(_name,(void*)cnt);3422}3423}34243425//------------------------------build_instr_pred-------------------------------3426// Build a path to 'name' in buf. Actually only build if cnt is zero, so we3427// can skip some leading instances of 'name'.3428int MatchNode::build_instr_pred( char *buf, const char *name, int cnt, int path_bitmask, int level) {3429if( _lChild ) {3430cnt = _lChild->build_instr_pred(buf, name, cnt, path_bitmask, level+1);3431if( cnt < 0 ) {3432return cnt; // Found it, all done3433}3434}3435if( _rChild ) {3436path_bitmask |= 1 << level;3437cnt = _rChild->build_instr_pred( buf, name, cnt, path_bitmask, level+1);3438if( cnt < 0 ) {3439return cnt; // Found it, all done3440}3441}3442if( !_lChild && !_rChild ) { // Found a leaf3443// Wrong name? Give up...3444if( strcmp(name,_name) ) return cnt;3445if( !cnt ) {3446for(int i = 0; i < level; i++) {3447int kid = path_bitmask & (1 << i);3448if (0 == kid) {3449strcpy( buf, "_kids[0]->" );3450} else {3451strcpy( buf, "_kids[1]->" );3452}3453buf += 10;3454}3455strcpy( buf, "_leaf" );3456}3457return cnt-1;3458}3459return cnt;3460}346134623463//------------------------------build_internalop-------------------------------3464// Build string representation of subtree3465void MatchNode::build_internalop( ) {3466char *iop, *subtree;3467const char *lstr, *rstr;3468// Build string representation of subtree3469// Operation lchildType rchildType3470int len = (int)strlen(_opType) + 4;3471lstr = (_lChild) ? ((_lChild->_internalop) ?3472_lChild->_internalop : _lChild->_opType) : "";3473rstr = (_rChild) ? ((_rChild->_internalop) ?3474_rChild->_internalop : _rChild->_opType) : "";3475len += (int)strlen(lstr) + (int)strlen(rstr);3476subtree = (char *)AllocateHeap(len);3477sprintf(subtree,"_%s_%s_%s", _opType, lstr, rstr);3478// Hash the subtree string in _internalOps; if a name exists, use it3479iop = (char *)_AD._internalOps[subtree];3480// Else create a unique name, and add it to the hash table3481if (iop == NULL) {3482iop = subtree;3483_AD._internalOps.Insert(subtree, iop);3484_AD._internalOpNames.addName(iop);3485_AD._internalMatch.Insert(iop, this);3486}3487// Add the internal operand name to the MatchNode3488_internalop = iop;3489_result = iop;3490}349134923493void MatchNode::dump() {3494output(stderr);3495}34963497void MatchNode::output(FILE *fp) {3498if (_lChild==0 && _rChild==0) {3499fprintf(fp," %s",_name); // operand3500}3501else {3502fprintf(fp," (%s ",_name); // " (opcodeName "3503if(_lChild) _lChild->output(fp); // left operand3504if(_rChild) _rChild->output(fp); // right operand3505fprintf(fp,")"); // ")"3506}3507}35083509int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {3510static const char *needs_ideal_memory_list[] = {3511"StoreI","StoreL","StoreP","StoreN","StoreNKlass","StoreD","StoreF" ,3512"StoreB","StoreC","Store" ,"StoreFP",3513"LoadI", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,3514"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,3515"StoreVector", "LoadVector", "LoadVectorGather", "StoreVectorScatter", "LoadVectorMasked", "StoreVectorMasked",3516"LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",3517"LoadPLocked",3518"StorePConditional", "StoreIConditional", "StoreLConditional",3519"CompareAndSwapB", "CompareAndSwapS", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN",3520"WeakCompareAndSwapB", "WeakCompareAndSwapS", "WeakCompareAndSwapI", "WeakCompareAndSwapL", "WeakCompareAndSwapP", "WeakCompareAndSwapN",3521"CompareAndExchangeB", "CompareAndExchangeS", "CompareAndExchangeI", "CompareAndExchangeL", "CompareAndExchangeP", "CompareAndExchangeN",3522#if INCLUDE_SHENANDOAHGC3523"ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN",3524#endif3525"StoreCM",3526"GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP",3527"GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN",3528"ClearArray"3529};3530int cnt = sizeof(needs_ideal_memory_list)/sizeof(char*);3531if( strcmp(_opType,"PrefetchAllocation")==0 )3532return 1;3533if( strcmp(_opType,"CacheWB")==0 )3534return 1;3535if( strcmp(_opType,"CacheWBPreSync")==0 )3536return 1;3537if( strcmp(_opType,"CacheWBPostSync")==0 )3538return 1;3539if( _lChild ) {3540const char *opType = _lChild->_opType;3541for( int i=0; i<cnt; i++ )3542if( strcmp(opType,needs_ideal_memory_list[i]) == 0 )3543return 1;3544if( _lChild->needs_ideal_memory_edge(globals) )3545return 1;3546}3547if( _rChild ) {3548const char *opType = _rChild->_opType;3549for( int i=0; i<cnt; i++ )3550if( strcmp(opType,needs_ideal_memory_list[i]) == 0 )3551return 1;3552if( _rChild->needs_ideal_memory_edge(globals) )3553return 1;3554}35553556return 0;3557}35583559// TRUE if defines a derived oop, and so needs a base oop edge present3560// post-matching.3561int MatchNode::needs_base_oop_edge() const {3562if( !strcmp(_opType,"AddP") ) return 1;3563if( strcmp(_opType,"Set") ) return 0;3564return !strcmp(_rChild->_opType,"AddP");3565}35663567int InstructForm::needs_base_oop_edge(FormDict &globals) const {3568if( is_simple_chain_rule(globals) ) {3569const char *src = _matrule->_rChild->_opType;3570OperandForm *src_op = globals[src]->is_operand();3571assert( src_op, "Not operand class of chain rule" );3572return src_op->_matrule ? src_op->_matrule->needs_base_oop_edge() : 0;3573} // Else check instruction35743575return _matrule ? _matrule->needs_base_oop_edge() : 0;3576}357735783579//-------------------------cisc spilling methods-------------------------------3580// helper routines and methods for detecting cisc-spilling instructions3581//-------------------------cisc_spill_merge------------------------------------3582int MatchNode::cisc_spill_merge(int left_spillable, int right_spillable) {3583int cisc_spillable = Maybe_cisc_spillable;35843585// Combine results of left and right checks3586if( (left_spillable == Maybe_cisc_spillable) && (right_spillable == Maybe_cisc_spillable) ) {3587// neither side is spillable, nor prevents cisc spilling3588cisc_spillable = Maybe_cisc_spillable;3589}3590else if( (left_spillable == Maybe_cisc_spillable) && (right_spillable > Maybe_cisc_spillable) ) {3591// right side is spillable3592cisc_spillable = right_spillable;3593}3594else if( (right_spillable == Maybe_cisc_spillable) && (left_spillable > Maybe_cisc_spillable) ) {3595// left side is spillable3596cisc_spillable = left_spillable;3597}3598else if( (left_spillable == Not_cisc_spillable) || (right_spillable == Not_cisc_spillable) ) {3599// left or right prevents cisc spilling this instruction3600cisc_spillable = Not_cisc_spillable;3601}3602else {3603// Only allow one to spill3604cisc_spillable = Not_cisc_spillable;3605}36063607return cisc_spillable;3608}36093610//-------------------------root_ops_match--------------------------------------3611bool static root_ops_match(FormDict &globals, const char *op1, const char *op2) {3612// Base Case: check that the current operands/operations match3613assert( op1, "Must have op's name");3614assert( op2, "Must have op's name");3615const Form *form1 = globals[op1];3616const Form *form2 = globals[op2];36173618return (form1 == form2);3619}36203621//-------------------------cisc_spill_match_node-------------------------------3622// Recursively check two MatchRules for legal conversion via cisc-spilling3623int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* ®_type) {3624int cisc_spillable = Maybe_cisc_spillable;3625int left_spillable = Maybe_cisc_spillable;3626int right_spillable = Maybe_cisc_spillable;36273628// Check that each has same number of operands at this level3629if( (_lChild && !(mRule2->_lChild)) || (_rChild && !(mRule2->_rChild)) )3630return Not_cisc_spillable;36313632// Base Case: check that the current operands/operations match3633// or are CISC spillable3634assert( _opType, "Must have _opType");3635assert( mRule2->_opType, "Must have _opType");3636const Form *form = globals[_opType];3637const Form *form2 = globals[mRule2->_opType];3638if( form == form2 ) {3639cisc_spillable = Maybe_cisc_spillable;3640} else {3641const InstructForm *form2_inst = form2 ? form2->is_instruction() : NULL;3642const char *name_left = mRule2->_lChild ? mRule2->_lChild->_opType : NULL;3643const char *name_right = mRule2->_rChild ? mRule2->_rChild->_opType : NULL;3644DataType data_type = Form::none;3645if (form->is_operand()) {3646// Make sure the loadX matches the type of the reg3647data_type = form->ideal_to_Reg_type(form->is_operand()->ideal_type(globals));3648}3649// Detect reg vs (loadX memory)3650if( form->is_cisc_reg(globals)3651&& form2_inst3652&& data_type != Form::none3653&& (is_load_from_memory(mRule2->_opType) == data_type) // reg vs. (load memory)3654&& (name_left != NULL) // NOT (load)3655&& (name_right == NULL) ) { // NOT (load memory foo)3656const Form *form2_left = globals[name_left];3657if( form2_left && form2_left->is_cisc_mem(globals) ) {3658cisc_spillable = Is_cisc_spillable;3659operand = _name;3660reg_type = _result;3661return Is_cisc_spillable;3662} else {3663cisc_spillable = Not_cisc_spillable;3664}3665}3666// Detect reg vs memory3667else if (form->is_cisc_reg(globals) && form2 != NULL && form2->is_cisc_mem(globals)) {3668cisc_spillable = Is_cisc_spillable;3669operand = _name;3670reg_type = _result;3671return Is_cisc_spillable;3672} else {3673cisc_spillable = Not_cisc_spillable;3674}3675}36763677// If cisc is still possible, check rest of tree3678if( cisc_spillable == Maybe_cisc_spillable ) {3679// Check that each has same number of operands at this level3680if( (_lChild && !(mRule2->_lChild)) || (_rChild && !(mRule2->_rChild)) ) return Not_cisc_spillable;36813682// Check left operands3683if( (_lChild == NULL) && (mRule2->_lChild == NULL) ) {3684left_spillable = Maybe_cisc_spillable;3685} else if (_lChild != NULL) {3686left_spillable = _lChild->cisc_spill_match(globals, registers, mRule2->_lChild, operand, reg_type);3687}36883689// Check right operands3690if( (_rChild == NULL) && (mRule2->_rChild == NULL) ) {3691right_spillable = Maybe_cisc_spillable;3692} else if (_rChild != NULL) {3693right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type);3694}36953696// Combine results of left and right checks3697cisc_spillable = cisc_spill_merge(left_spillable, right_spillable);3698}36993700return cisc_spillable;3701}37023703//---------------------------cisc_spill_match_rule------------------------------3704// Recursively check two MatchRules for legal conversion via cisc-spilling3705// This method handles the root of Match tree,3706// general recursive checks done in MatchNode3707int MatchRule::matchrule_cisc_spill_match(FormDict& globals, RegisterForm* registers,3708MatchRule* mRule2, const char* &operand,3709const char* ®_type) {3710int cisc_spillable = Maybe_cisc_spillable;3711int left_spillable = Maybe_cisc_spillable;3712int right_spillable = Maybe_cisc_spillable;37133714// Check that each sets a result3715if( !(sets_result() && mRule2->sets_result()) ) return Not_cisc_spillable;3716// Check that each has same number of operands at this level3717if( (_lChild && !(mRule2->_lChild)) || (_rChild && !(mRule2->_rChild)) ) return Not_cisc_spillable;37183719// Check left operands: at root, must be target of 'Set'3720if( (_lChild == NULL) || (mRule2->_lChild == NULL) ) {3721left_spillable = Not_cisc_spillable;3722} else {3723// Do not support cisc-spilling instruction's target location3724if( root_ops_match(globals, _lChild->_opType, mRule2->_lChild->_opType) ) {3725left_spillable = Maybe_cisc_spillable;3726} else {3727left_spillable = Not_cisc_spillable;3728}3729}37303731// Check right operands: recursive walk to identify reg->mem operand3732if (_rChild == NULL) {3733if (mRule2->_rChild == NULL) {3734right_spillable = Maybe_cisc_spillable;3735} else {3736assert(0, "_rChild should not be NULL");3737}3738} else {3739right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type);3740}37413742// Combine results of left and right checks3743cisc_spillable = cisc_spill_merge(left_spillable, right_spillable);37443745return cisc_spillable;3746}37473748//----------------------------- equivalent ------------------------------------3749// Recursively check to see if two match rules are equivalent.3750// This rule handles the root.3751bool MatchRule::equivalent(FormDict &globals, MatchNode *mRule2) {3752// Check that each sets a result3753if (sets_result() != mRule2->sets_result()) {3754return false;3755}37563757// Check that the current operands/operations match3758assert( _opType, "Must have _opType");3759assert( mRule2->_opType, "Must have _opType");3760const Form *form = globals[_opType];3761const Form *form2 = globals[mRule2->_opType];3762if( form != form2 ) {3763return false;3764}37653766if (_lChild ) {3767if( !_lChild->equivalent(globals, mRule2->_lChild) )3768return false;3769} else if (mRule2->_lChild) {3770return false; // I have NULL left child, mRule2 has non-NULL left child.3771}37723773if (_rChild ) {3774if( !_rChild->equivalent(globals, mRule2->_rChild) )3775return false;3776} else if (mRule2->_rChild) {3777return false; // I have NULL right child, mRule2 has non-NULL right child.3778}37793780// We've made it through the gauntlet.3781return true;3782}37833784//----------------------------- equivalent ------------------------------------3785// Recursively check to see if two match rules are equivalent.3786// This rule handles the operands.3787bool MatchNode::equivalent(FormDict &globals, MatchNode *mNode2) {3788if( !mNode2 )3789return false;37903791// Check that the current operands/operations match3792assert( _opType, "Must have _opType");3793assert( mNode2->_opType, "Must have _opType");3794const Form *form = globals[_opType];3795const Form *form2 = globals[mNode2->_opType];3796if( form != form2 ) {3797return false;3798}37993800// Check that their children also match3801if (_lChild ) {3802if( !_lChild->equivalent(globals, mNode2->_lChild) )3803return false;3804} else if (mNode2->_lChild) {3805return false; // I have NULL left child, mNode2 has non-NULL left child.3806}38073808if (_rChild ) {3809if( !_rChild->equivalent(globals, mNode2->_rChild) )3810return false;3811} else if (mNode2->_rChild) {3812return false; // I have NULL right child, mNode2 has non-NULL right child.3813}38143815// We've made it through the gauntlet.3816return true;3817}38183819//-------------------------- has_commutative_op -------------------------------3820// Recursively check for commutative operations with subtree operands3821// which could be swapped.3822void MatchNode::count_commutative_op(int& count) {3823static const char *commut_op_list[] = {3824"AddI","AddL","AddF","AddD",3825"AddVB","AddVS","AddVI","AddVL","AddVF","AddVD",3826"AndI","AndL",3827"AndV",3828"MaxI","MinI","MaxF","MinF","MaxD","MinD",3829"MaxV", "MinV",3830"MulI","MulL","MulF","MulD",3831"MulVB","MulVS","MulVI","MulVL","MulVF","MulVD",3832"OrI","OrL",3833"OrV",3834"XorI","XorL",3835"XorV"3836};3837int cnt = sizeof(commut_op_list)/sizeof(char*);38383839if( _lChild && _rChild && (_lChild->_lChild || _rChild->_lChild) ) {3840// Don't swap if right operand is an immediate constant.3841bool is_const = false;3842if( _rChild->_lChild == NULL && _rChild->_rChild == NULL ) {3843FormDict &globals = _AD.globalNames();3844const Form *form = globals[_rChild->_opType];3845if ( form ) {3846OperandForm *oper = form->is_operand();3847if( oper && oper->interface_type(globals) == Form::constant_interface )3848is_const = true;3849}3850}3851if( !is_const ) {3852for( int i=0; i<cnt; i++ ) {3853if( strcmp(_opType, commut_op_list[i]) == 0 ) {3854count++;3855_commutative_id = count; // id should be > 03856break;3857}3858}3859}3860}3861if( _lChild )3862_lChild->count_commutative_op(count);3863if( _rChild )3864_rChild->count_commutative_op(count);3865}38663867//-------------------------- swap_commutative_op ------------------------------3868// Recursively swap specified commutative operation with subtree operands.3869void MatchNode::swap_commutative_op(bool atroot, int id) {3870if( _commutative_id == id ) { // id should be > 03871assert(_lChild && _rChild && (_lChild->_lChild || _rChild->_lChild ),3872"not swappable operation");3873MatchNode* tmp = _lChild;3874_lChild = _rChild;3875_rChild = tmp;3876// Don't exit here since we need to build internalop.3877}38783879bool is_set = ( strcmp(_opType, "Set") == 0 );3880if( _lChild )3881_lChild->swap_commutative_op(is_set, id);3882if( _rChild )3883_rChild->swap_commutative_op(is_set, id);38843885// If not the root, reduce this subtree to an internal operand3886if( !atroot && (_lChild || _rChild) ) {3887build_internalop();3888}3889}38903891//-------------------------- swap_commutative_op ------------------------------3892// Recursively swap specified commutative operation with subtree operands.3893void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) {3894assert(match_rules_cnt < 100," too many match rule clones");3895// Clone3896MatchRule* clone = new MatchRule(_AD, this);3897// Swap operands of commutative operation3898((MatchNode*)clone)->swap_commutative_op(true, count);3899char* buf = (char*) AllocateHeap(strlen(instr_ident) + 4);3900sprintf(buf, "%s_%d", instr_ident, match_rules_cnt++);3901clone->_result = buf;39023903clone->_next = this->_next;3904this-> _next = clone;3905if( (--count) > 0 ) {3906this-> matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);3907clone->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);3908}3909}39103911//------------------------------MatchRule--------------------------------------3912MatchRule::MatchRule(ArchDesc &ad)3913: MatchNode(ad), _depth(0), _construct(NULL), _numchilds(0) {3914_next = NULL;3915}39163917MatchRule::MatchRule(ArchDesc &ad, MatchRule* mRule)3918: MatchNode(ad, *mRule, 0), _depth(mRule->_depth),3919_construct(mRule->_construct), _numchilds(mRule->_numchilds) {3920_next = NULL;3921}39223923MatchRule::MatchRule(ArchDesc &ad, MatchNode* mroot, int depth, char *cnstr,3924int numleaves)3925: MatchNode(ad,*mroot), _depth(depth), _construct(cnstr),3926_numchilds(0) {3927_next = NULL;3928mroot->_lChild = NULL;3929mroot->_rChild = NULL;3930delete mroot;3931_numleaves = numleaves;3932_numchilds = (_lChild ? 1 : 0) + (_rChild ? 1 : 0);3933}3934MatchRule::~MatchRule() {3935}39363937// Recursive call collecting info on top-level operands, not transitive.3938// Implementation does not modify state of internal structures.3939void MatchRule::append_components(FormDict& locals, ComponentList& components, bool def_flag) const {3940assert (_name != NULL, "MatchNode::build_components encountered empty node\n");39413942MatchNode::append_components(locals, components,3943false /* not necessarily a def */);3944}39453946// Recursive call on all operands' match rules in my match rule.3947// Implementation does not modify state of internal structures since they3948// can be shared.3949// The MatchNode that is called first treats its3950bool MatchRule::base_operand(uint &position0, FormDict &globals,3951const char *&result, const char * &name,3952const char * &opType)const{3953uint position = position0;39543955return (MatchNode::base_operand( position, globals, result, name, opType));3956}395739583959bool MatchRule::is_base_register(FormDict &globals) const {3960uint position = 1;3961const char *result = NULL;3962const char *name = NULL;3963const char *opType = NULL;3964if (!base_operand(position, globals, result, name, opType)) {3965position = 0;3966if( base_operand(position, globals, result, name, opType) &&3967(strcmp(opType,"RegI")==0 ||3968strcmp(opType,"RegP")==0 ||3969strcmp(opType,"RegN")==0 ||3970strcmp(opType,"RegL")==0 ||3971strcmp(opType,"RegF")==0 ||3972strcmp(opType,"RegD")==0 ||3973strcmp(opType,"RegVectMask")==0 ||3974strcmp(opType,"VecA")==0 ||3975strcmp(opType,"VecS")==0 ||3976strcmp(opType,"VecD")==0 ||3977strcmp(opType,"VecX")==0 ||3978strcmp(opType,"VecY")==0 ||3979strcmp(opType,"VecZ")==0 ||3980strcmp(opType,"Reg" )==0) ) {3981return 1;3982}3983}3984return 0;3985}39863987Form::DataType MatchRule::is_base_constant(FormDict &globals) const {3988uint position = 1;3989const char *result = NULL;3990const char *name = NULL;3991const char *opType = NULL;3992if (!base_operand(position, globals, result, name, opType)) {3993position = 0;3994if (base_operand(position, globals, result, name, opType)) {3995return ideal_to_const_type(opType);3996}3997}3998return Form::none;3999}40004001bool MatchRule::is_chain_rule(FormDict &globals) const {40024003// Check for chain rule, and do not generate a match list for it4004if ((_lChild == NULL) && (_rChild == NULL) ) {4005const Form *form = globals[_opType];4006// If this is ideal, then it is a base match, not a chain rule.4007if ( form && form->is_operand() && (!form->ideal_only())) {4008return true;4009}4010}4011// Check for "Set" form of chain rule, and do not generate a match list4012if (_rChild) {4013const char *rch = _rChild->_opType;4014const Form *form = globals[rch];4015if ((!strcmp(_opType,"Set") &&4016((form) && form->is_operand()))) {4017return true;4018}4019}4020return false;4021}40224023int MatchRule::is_ideal_copy() const {4024if (is_chain_rule(_AD.globalNames()) &&4025_lChild && strncmp(_lChild->_opType, "stackSlot", 9) == 0) {4026return 1;4027}4028return 0;4029}40304031int MatchRule::is_expensive() const {4032if( _rChild ) {4033const char *opType = _rChild->_opType;4034if( strcmp(opType,"AtanD")==0 ||4035strcmp(opType,"DivD")==0 ||4036strcmp(opType,"DivF")==0 ||4037strcmp(opType,"DivI")==0 ||4038strcmp(opType,"Log10D")==0 ||4039strcmp(opType,"ModD")==0 ||4040strcmp(opType,"ModF")==0 ||4041strcmp(opType,"ModI")==0 ||4042strcmp(opType,"SqrtD")==0 ||4043strcmp(opType,"SqrtF")==0 ||4044strcmp(opType,"TanD")==0 ||4045strcmp(opType,"ConvD2F")==0 ||4046strcmp(opType,"ConvD2I")==0 ||4047strcmp(opType,"ConvD2L")==0 ||4048strcmp(opType,"ConvF2D")==0 ||4049strcmp(opType,"ConvF2I")==0 ||4050strcmp(opType,"ConvF2L")==0 ||4051strcmp(opType,"ConvI2D")==0 ||4052strcmp(opType,"ConvI2F")==0 ||4053strcmp(opType,"ConvI2L")==0 ||4054strcmp(opType,"ConvL2D")==0 ||4055strcmp(opType,"ConvL2F")==0 ||4056strcmp(opType,"ConvL2I")==0 ||4057strcmp(opType,"DecodeN")==0 ||4058strcmp(opType,"EncodeP")==0 ||4059strcmp(opType,"EncodePKlass")==0 ||4060strcmp(opType,"DecodeNKlass")==0 ||4061strcmp(opType,"FmaD") == 0 ||4062strcmp(opType,"FmaF") == 0 ||4063strcmp(opType,"RoundDouble")==0 ||4064strcmp(opType,"RoundDoubleMode")==0 ||4065strcmp(opType,"RoundFloat")==0 ||4066strcmp(opType,"ReverseBytesI")==0 ||4067strcmp(opType,"ReverseBytesL")==0 ||4068strcmp(opType,"ReverseBytesUS")==0 ||4069strcmp(opType,"ReverseBytesS")==0 ||4070strcmp(opType,"ReplicateB")==0 ||4071strcmp(opType,"ReplicateS")==0 ||4072strcmp(opType,"ReplicateI")==0 ||4073strcmp(opType,"ReplicateL")==0 ||4074strcmp(opType,"ReplicateF")==0 ||4075strcmp(opType,"ReplicateD")==0 ||4076strcmp(opType,"AddReductionVI")==0 ||4077strcmp(opType,"AddReductionVL")==0 ||4078strcmp(opType,"AddReductionVF")==0 ||4079strcmp(opType,"AddReductionVD")==0 ||4080strcmp(opType,"MulReductionVI")==0 ||4081strcmp(opType,"MulReductionVL")==0 ||4082strcmp(opType,"MulReductionVF")==0 ||4083strcmp(opType,"MulReductionVD")==0 ||4084strcmp(opType,"MinReductionV")==0 ||4085strcmp(opType,"MaxReductionV")==0 ||4086strcmp(opType,"AndReductionV")==0 ||4087strcmp(opType,"OrReductionV")==0 ||4088strcmp(opType,"XorReductionV")==0 ||40890 /* 0 to line up columns nicely */ )4090return 1;4091}4092return 0;4093}40944095bool MatchRule::is_ideal_if() const {4096if( !_opType ) return false;4097return4098!strcmp(_opType,"If" ) ||4099!strcmp(_opType,"CountedLoopEnd");4100}41014102bool MatchRule::is_ideal_fastlock() const {4103if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4104return (strcmp(_rChild->_opType,"FastLock") == 0);4105}4106return false;4107}41084109bool MatchRule::is_ideal_membar() const {4110if( !_opType ) return false;4111return4112!strcmp(_opType,"MemBarAcquire") ||4113!strcmp(_opType,"MemBarRelease") ||4114!strcmp(_opType,"MemBarAcquireLock") ||4115!strcmp(_opType,"MemBarReleaseLock") ||4116!strcmp(_opType,"LoadFence" ) ||4117!strcmp(_opType,"StoreFence") ||4118!strcmp(_opType,"MemBarVolatile") ||4119!strcmp(_opType,"MemBarCPUOrder") ||4120!strcmp(_opType,"MemBarStoreStore") ||4121!strcmp(_opType,"OnSpinWait");4122}41234124bool MatchRule::is_ideal_loadPC() const {4125if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4126return (strcmp(_rChild->_opType,"LoadPC") == 0);4127}4128return false;4129}41304131bool MatchRule::is_ideal_box() const {4132if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4133return (strcmp(_rChild->_opType,"Box") == 0);4134}4135return false;4136}41374138bool MatchRule::is_ideal_goto() const {4139bool ideal_goto = false;41404141if( _opType && (strcmp(_opType,"Goto") == 0) ) {4142ideal_goto = true;4143}4144return ideal_goto;4145}41464147bool MatchRule::is_ideal_jump() const {4148if( _opType ) {4149if( !strcmp(_opType,"Jump") )4150return true;4151}4152return false;4153}41544155bool MatchRule::is_ideal_bool() const {4156if( _opType ) {4157if( !strcmp(_opType,"Bool") )4158return true;4159}4160return false;4161}416241634164Form::DataType MatchRule::is_ideal_load() const {4165Form::DataType ideal_load = Form::none;41664167if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4168const char *opType = _rChild->_opType;4169ideal_load = is_load_from_memory(opType);4170}41714172return ideal_load;4173}41744175bool MatchRule::is_vector() const {4176static const char *vector_list[] = {4177"AddVB","AddVS","AddVI","AddVL","AddVF","AddVD",4178"SubVB","SubVS","SubVI","SubVL","SubVF","SubVD",4179"MulVB","MulVS","MulVI","MulVL","MulVF","MulVD",4180"CMoveVD", "CMoveVF",4181"DivVF","DivVD",4182"AbsVB","AbsVS","AbsVI","AbsVL","AbsVF","AbsVD",4183"NegVF","NegVD","NegVI",4184"SqrtVD","SqrtVF",4185"AndV" ,"XorV" ,"OrV",4186"MaxV", "MinV",4187"AddReductionVI", "AddReductionVL",4188"AddReductionVF", "AddReductionVD",4189"MulReductionVI", "MulReductionVL",4190"MulReductionVF", "MulReductionVD",4191"MaxReductionV", "MinReductionV",4192"AndReductionV", "OrReductionV", "XorReductionV",4193"MulAddVS2VI", "MacroLogicV",4194"LShiftCntV","RShiftCntV",4195"LShiftVB","LShiftVS","LShiftVI","LShiftVL",4196"RShiftVB","RShiftVS","RShiftVI","RShiftVL",4197"URShiftVB","URShiftVS","URShiftVI","URShiftVL",4198"ReplicateB","ReplicateS","ReplicateI","ReplicateL","ReplicateF","ReplicateD",4199"RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector",4200"LoadVectorGather", "StoreVectorScatter",4201"VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",4202"VectorRearrange","VectorLoadShuffle", "VectorLoadConst",4203"VectorCastB2X", "VectorCastS2X", "VectorCastI2X",4204"VectorCastL2X", "VectorCastF2X", "VectorCastD2X",4205"VectorMaskWrapper", "VectorMaskCmp", "VectorReinterpret","LoadVectorMasked","StoreVectorMasked",4206"FmaVD", "FmaVF","PopCountVI",4207// Next are not supported currently.4208"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",4209"ExtractB","ExtractUB","ExtractC","ExtractS","ExtractI","ExtractL","ExtractF","ExtractD",4210"VectorMaskCast"4211};4212int cnt = sizeof(vector_list)/sizeof(char*);4213if (_rChild) {4214const char *opType = _rChild->_opType;4215for (int i=0; i<cnt; i++)4216if (strcmp(opType,vector_list[i]) == 0)4217return true;4218}4219return false;4220}422142224223bool MatchRule::skip_antidep_check() const {4224// Some loads operate on what is effectively immutable memory so we4225// should skip the anti dep computations. For some of these nodes4226// the rewritable field keeps the anti dep logic from triggering but4227// for certain kinds of LoadKlass it does not since they are4228// actually reading memory which could be rewritten by the runtime,4229// though never by generated code. This disables it uniformly for4230// the nodes that behave like this: LoadKlass, LoadNKlass and4231// LoadRange.4232if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4233const char *opType = _rChild->_opType;4234if (strcmp("LoadKlass", opType) == 0 ||4235strcmp("LoadNKlass", opType) == 0 ||4236strcmp("LoadRange", opType) == 0) {4237return true;4238}4239}42404241return false;4242}424342444245Form::DataType MatchRule::is_ideal_store() const {4246Form::DataType ideal_store = Form::none;42474248if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4249const char *opType = _rChild->_opType;4250ideal_store = is_store_to_memory(opType);4251}42524253return ideal_store;4254}425542564257void MatchRule::dump() {4258output(stderr);4259}42604261// Write just one line.4262void MatchRule::output_short(FILE *fp) {4263fprintf(fp,"MatchRule: ( %s",_name);4264if (_lChild) _lChild->output(fp);4265if (_rChild) _rChild->output(fp);4266fprintf(fp," )");4267}42684269void MatchRule::output(FILE *fp) {4270output_short(fp);4271fprintf(fp,"\n nesting depth = %d\n", _depth);4272if (_result) fprintf(fp," Result Type = %s", _result);4273fprintf(fp,"\n");4274}42754276//------------------------------Attribute--------------------------------------4277Attribute::Attribute(char *id, char* val, int type)4278: _ident(id), _val(val), _atype(type) {4279}4280Attribute::~Attribute() {4281}42824283int Attribute::int_val(ArchDesc &ad) {4284// Make sure it is an integer constant:4285int result = 0;4286if (!_val || !ADLParser::is_int_token(_val, result)) {4287ad.syntax_err(0, "Attribute %s must have an integer value: %s",4288_ident, _val ? _val : "");4289}4290return result;4291}42924293void Attribute::dump() {4294output(stderr);4295} // Debug printer42964297// Write to output files4298void Attribute::output(FILE *fp) {4299fprintf(fp,"Attribute: %s %s\n", (_ident?_ident:""), (_val?_val:""));4300}43014302//------------------------------FormatRule----------------------------------4303FormatRule::FormatRule(char *temp)4304: _temp(temp) {4305}4306FormatRule::~FormatRule() {4307}43084309void FormatRule::dump() {4310output(stderr);4311}43124313// Write to output files4314void FormatRule::output(FILE *fp) {4315fprintf(fp,"\nFormat Rule: \n%s", (_temp?_temp:""));4316fprintf(fp,"\n");4317}431843194320