Path: blob/master/src/hotspot/share/adlc/formssel.cpp
64440 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,"VectorCmpMasked")||792!strcmp(_matrule->_rChild->_opType,"VectorMaskGen")||793!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") ||794!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true;795else if ( is_ideal_load() == Form::idealP ) return true;796else if ( is_ideal_store() != Form::none ) return true;797798if (needs_base_oop_edge(globals)) return true;799800if (is_vector()) return true;801if (is_mach_constant()) return true;802803return false;804}805806807// Access instr_cost attribute or return NULL.808const char* InstructForm::cost() {809for (Attribute* cur = _attribs; cur != NULL; cur = (Attribute*)cur->_next) {810if( strcmp(cur->_ident,AttributeForm::_ins_cost) == 0 ) {811return cur->_val;812}813}814return NULL;815}816817// Return count of top-level operands.818uint InstructForm::num_opnds() {819int num_opnds = _components.num_operands();820821// Need special handling for matching some ideal nodes822// i.e. Matching a return node823/*824if( _matrule ) {825if( strcmp(_matrule->_opType,"Return" )==0 ||826strcmp(_matrule->_opType,"Halt" )==0 )827return 3;828}829*/830return num_opnds;831}832833const char* InstructForm::opnd_ident(int idx) {834return _components.at(idx)->_name;835}836837const char* InstructForm::unique_opnd_ident(uint idx) {838uint i;839for (i = 1; i < num_opnds(); ++i) {840if (unique_opnds_idx(i) == idx) {841break;842}843}844return (_components.at(i) != NULL) ? _components.at(i)->_name : "";845}846847// Return count of unmatched operands.848uint InstructForm::num_post_match_opnds() {849uint num_post_match_opnds = _components.count();850uint num_match_opnds = _components.match_count();851num_post_match_opnds = num_post_match_opnds - num_match_opnds;852853return num_post_match_opnds;854}855856// Return the number of leaves below this complex operand857uint InstructForm::num_consts(FormDict &globals) const {858if ( ! _matrule) return 0;859860// This is a recursive invocation on all operands in the matchrule861return _matrule->num_consts(globals);862}863864// Constants in match rule with specified type865uint InstructForm::num_consts(FormDict &globals, Form::DataType type) const {866if ( ! _matrule) return 0;867868// This is a recursive invocation on all operands in the matchrule869return _matrule->num_consts(globals, type);870}871872873// Return the register class associated with 'leaf'.874const char *InstructForm::out_reg_class(FormDict &globals) {875assert( false, "InstructForm::out_reg_class(FormDict &globals); Not Implemented");876877return NULL;878}879880881882// Lookup the starting position of inputs we are interested in wrt. ideal nodes883uint InstructForm::oper_input_base(FormDict &globals) {884if( !_matrule ) return 1; // Skip control for most nodes885886// Need special handling for matching some ideal nodes887// i.e. Matching a return node888if( strcmp(_matrule->_opType,"Return" )==0 ||889strcmp(_matrule->_opType,"Rethrow" )==0 ||890strcmp(_matrule->_opType,"TailCall" )==0 ||891strcmp(_matrule->_opType,"TailJump" )==0 ||892strcmp(_matrule->_opType,"SafePoint" )==0 ||893strcmp(_matrule->_opType,"Halt" )==0 )894return AdlcVMDeps::Parms; // Skip the machine-state edges895896if( _matrule->_rChild &&897( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ||898strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||899strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||900strcmp(_matrule->_rChild->_opType,"StrInflatedCopy" )==0 ||901strcmp(_matrule->_rChild->_opType,"StrCompressedCopy" )==0 ||902strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 ||903strcmp(_matrule->_rChild->_opType,"StrIndexOfChar")==0 ||904strcmp(_matrule->_rChild->_opType,"HasNegatives")==0 ||905strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) {906// String.(compareTo/equals/indexOf) and Arrays.equals907// and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray908// take 1 control and 1 memory edges.909// Also String.(compressedCopy/inflatedCopy).910return 2;911}912913// Check for handling of 'Memory' input/edge in the ideal world.914// The AD file writer is shielded from knowledge of these edges.915int base = 1; // Skip control916base += _matrule->needs_ideal_memory_edge(globals);917918// Also skip the base-oop value for uses of derived oops.919// The AD file writer is shielded from knowledge of these edges.920base += needs_base_oop_edge(globals);921922return base;923}924925// This function determines the order of the MachOper in _opnds[]926// by writing the operand names into the _components list.927//928// Implementation does not modify state of internal structures929void InstructForm::build_components() {930// Add top-level operands to the components931if (_matrule) _matrule->append_components(_localNames, _components);932933// Add parameters that "do not appear in match rule".934bool has_temp = false;935const char *name;936const char *kill_name = NULL;937for (_parameters.reset(); (name = _parameters.iter()) != NULL;) {938OpClassForm *opForm = _localNames[name]->is_opclass();939assert(opForm != NULL, "sanity");940941Effect* e = NULL;942{943const Form* form = _effects[name];944e = form ? form->is_effect() : NULL;945}946947if (e != NULL) {948has_temp |= e->is(Component::TEMP);949950// KILLs must be declared after any TEMPs because TEMPs are real951// uses so their operand numbering must directly follow the real952// inputs from the match rule. Fixing the numbering seems953// complex so simply enforce the restriction during parse.954if (kill_name != NULL &&955e->isa(Component::TEMP) && !e->isa(Component::DEF)) {956OpClassForm* kill = _localNames[kill_name]->is_opclass();957assert(kill != NULL, "sanity");958globalAD->syntax_err(_linenum, "%s: %s %s must be at the end of the argument list\n",959_ident, kill->_ident, kill_name);960} else if (e->isa(Component::KILL) && !e->isa(Component::USE)) {961kill_name = name;962}963}964965const Component *component = _components.search(name);966if ( component == NULL ) {967if (e) {968_components.insert(name, opForm->_ident, e->_use_def, false);969component = _components.search(name);970if (component->isa(Component::USE) && !component->isa(Component::TEMP) && _matrule) {971const Form *form = globalAD->globalNames()[component->_type];972assert( form, "component type must be a defined form");973OperandForm *op = form->is_operand();974if (op->_interface && op->_interface->is_RegInterface()) {975globalAD->syntax_err(_linenum, "%s: illegal USE of non-input: %s %s\n",976_ident, opForm->_ident, name);977}978}979} else {980// This would be a nice warning but it triggers in a few places in a benign way981// if (_matrule != NULL && !expands()) {982// globalAD->syntax_err(_linenum, "%s: %s %s not mentioned in effect or match rule\n",983// _ident, opForm->_ident, name);984// }985_components.insert(name, opForm->_ident, Component::INVALID, false);986}987}988else if (e) {989// Component was found in the list990// Check if there is a new effect that requires an extra component.991// This happens when adding 'USE' to a component that is not yet one.992if ((!component->isa( Component::USE) && ((e->_use_def & Component::USE) != 0))) {993if (component->isa(Component::USE) && _matrule) {994const Form *form = globalAD->globalNames()[component->_type];995assert( form, "component type must be a defined form");996OperandForm *op = form->is_operand();997if (op->_interface && op->_interface->is_RegInterface()) {998globalAD->syntax_err(_linenum, "%s: illegal USE of non-input: %s %s\n",999_ident, opForm->_ident, name);1000}1001}1002_components.insert(name, opForm->_ident, e->_use_def, false);1003} else {1004Component *comp = (Component*)component;1005comp->promote_use_def_info(e->_use_def);1006}1007// Component positions are zero based.1008int pos = _components.operand_position(name);1009assert( ! (component->isa(Component::DEF) && (pos >= 1)),1010"Component::DEF can only occur in the first position");1011}1012}10131014// Resolving the interactions between expand rules and TEMPs would1015// be complex so simply disallow it.1016if (_matrule == NULL && has_temp) {1017globalAD->syntax_err(_linenum, "%s: TEMPs without match rule isn't supported\n", _ident);1018}10191020return;1021}10221023// Return zero-based position in component list; -1 if not in list.1024int InstructForm::operand_position(const char *name, int usedef) {1025return unique_opnds_idx(_components.operand_position(name, usedef, this));1026}10271028int InstructForm::operand_position_format(const char *name) {1029return unique_opnds_idx(_components.operand_position_format(name, this));1030}10311032// Return zero-based position in component list; -1 if not in list.1033int InstructForm::label_position() {1034return unique_opnds_idx(_components.label_position());1035}10361037int InstructForm::method_position() {1038return unique_opnds_idx(_components.method_position());1039}10401041// Return number of relocation entries needed for this instruction.1042uint InstructForm::reloc(FormDict &globals) {1043uint reloc_entries = 0;1044// Check for "Call" nodes1045if ( is_ideal_call() ) ++reloc_entries;1046if ( is_ideal_return() ) ++reloc_entries;1047if ( is_ideal_safepoint() ) ++reloc_entries;104810491050// Check if operands MAYBE oop pointers, by checking for ConP elements1051// Proceed through the leaves of the match-tree and check for ConPs1052if ( _matrule != NULL ) {1053uint position = 0;1054const char *result = NULL;1055const char *name = NULL;1056const char *opType = NULL;1057while (_matrule->base_operand(position, globals, result, name, opType)) {1058if ( strcmp(opType,"ConP") == 0 ) {1059++reloc_entries;1060}1061++position;1062}1063}10641065// Above is only a conservative estimate1066// because it did not check contents of operand classes.1067// !!!!! !!!!!1068// Add 1 to reloc info for each operand class in the component list.1069Component *comp;1070_components.reset();1071while ( (comp = _components.iter()) != NULL ) {1072const Form *form = globals[comp->_type];1073assert( form, "Did not find component's type in global names");1074const OpClassForm *opc = form->is_opclass();1075const OperandForm *oper = form->is_operand();1076if ( opc && (oper == NULL) ) {1077++reloc_entries;1078} else if ( oper ) {1079// floats and doubles loaded out of method's constant pool require reloc info1080Form::DataType type = oper->is_base_constant(globals);1081if ( (type == Form::idealF) || (type == Form::idealD) ) {1082++reloc_entries;1083}1084}1085}10861087// Float and Double constants may come from the CodeBuffer table1088// and require relocatable addresses for access1089// !!!!!1090// Check for any component being an immediate float or double.1091Form::DataType data_type = is_chain_of_constant(globals);1092if( data_type==idealD || data_type==idealF ) {1093reloc_entries++;1094}10951096return reloc_entries;1097}10981099// Utility function defined in archDesc.cpp1100extern bool is_def(int usedef);11011102// Return the result of reducing an instruction1103const char *InstructForm::reduce_result() {1104const char* result = "Universe"; // default1105_components.reset();1106Component *comp = _components.iter();1107if (comp != NULL && comp->isa(Component::DEF)) {1108result = comp->_type;1109// Override this if the rule is a store operation:1110if (_matrule && _matrule->_rChild &&1111is_store_to_memory(_matrule->_rChild->_opType))1112result = "Universe";1113}1114return result;1115}11161117// Return the name of the operand on the right hand side of the binary match1118// Return NULL if there is no right hand side1119const char *InstructForm::reduce_right(FormDict &globals) const {1120if( _matrule == NULL ) return NULL;1121return _matrule->reduce_right(globals);1122}11231124// Similar for left1125const char *InstructForm::reduce_left(FormDict &globals) const {1126if( _matrule == NULL ) return NULL;1127return _matrule->reduce_left(globals);1128}112911301131// Base class for this instruction, MachNode except for calls1132const char *InstructForm::mach_base_class(FormDict &globals) const {1133if( is_ideal_call() == Form::JAVA_STATIC ) {1134return "MachCallStaticJavaNode";1135}1136else if( is_ideal_call() == Form::JAVA_DYNAMIC ) {1137return "MachCallDynamicJavaNode";1138}1139else if( is_ideal_call() == Form::JAVA_RUNTIME ) {1140return "MachCallRuntimeNode";1141}1142else if( is_ideal_call() == Form::JAVA_LEAF ) {1143return "MachCallLeafNode";1144}1145else if( is_ideal_call() == Form::JAVA_NATIVE ) {1146return "MachCallNativeNode";1147}1148else if (is_ideal_return()) {1149return "MachReturnNode";1150}1151else if (is_ideal_halt()) {1152return "MachHaltNode";1153}1154else if (is_ideal_safepoint()) {1155return "MachSafePointNode";1156}1157else if (is_ideal_if()) {1158return "MachIfNode";1159}1160else if (is_ideal_goto()) {1161return "MachGotoNode";1162}1163else if (is_ideal_fastlock()) {1164return "MachFastLockNode";1165}1166else if (is_ideal_nop()) {1167return "MachNopNode";1168}1169else if( is_ideal_membar()) {1170return "MachMemBarNode";1171}1172else if (is_ideal_jump()) {1173return "MachJumpNode";1174}1175else if (is_mach_constant()) {1176return "MachConstantNode";1177}1178else if (captures_bottom_type(globals)) {1179return "MachTypeNode";1180} else {1181return "MachNode";1182}1183assert( false, "ShouldNotReachHere()");1184return NULL;1185}11861187// Compare the instruction predicates for textual equality1188bool equivalent_predicates( const InstructForm *instr1, const InstructForm *instr2 ) {1189const Predicate *pred1 = instr1->_predicate;1190const Predicate *pred2 = instr2->_predicate;1191if( pred1 == NULL && pred2 == NULL ) {1192// no predicates means they are identical1193return true;1194}1195if( pred1 != NULL && pred2 != NULL ) {1196// compare the predicates1197if (ADLParser::equivalent_expressions(pred1->_pred, pred2->_pred)) {1198return true;1199}1200}12011202return false;1203}12041205// Check if this instruction can cisc-spill to 'alternate'1206bool InstructForm::cisc_spills_to(ArchDesc &AD, InstructForm *instr) {1207assert( _matrule != NULL && instr->_matrule != NULL, "must have match rules");1208// Do not replace if a cisc-version has been found.1209if( cisc_spill_operand() != Not_cisc_spillable ) return false;12101211int cisc_spill_operand = Maybe_cisc_spillable;1212char *result = NULL;1213char *result2 = NULL;1214const char *op_name = NULL;1215const char *reg_type = NULL;1216FormDict &globals = AD.globalNames();1217cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type);1218if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != NULL) && equivalent_predicates(this, instr) ) {1219cisc_spill_operand = operand_position(op_name, Component::USE);1220int def_oper = operand_position(op_name, Component::DEF);1221if( def_oper == NameList::Not_in_list && instr->num_opnds() == num_opnds()) {1222// Do not support cisc-spilling for destination operands and1223// make sure they have the same number of operands.1224_cisc_spill_alternate = instr;1225instr->set_cisc_alternate(true);1226if( AD._cisc_spill_debug ) {1227fprintf(stderr, "Instruction %s cisc-spills-to %s\n", _ident, instr->_ident);1228fprintf(stderr, " using operand %s %s at index %d\n", reg_type, op_name, cisc_spill_operand);1229}1230// Record that a stack-version of the reg_mask is needed1231// !!!!!1232OperandForm *oper = (OperandForm*)(globals[reg_type]->is_operand());1233assert( oper != NULL, "cisc-spilling non operand");1234const char *reg_class_name = oper->constrained_reg_class();1235AD.set_stack_or_reg(reg_class_name);1236const char *reg_mask_name = AD.reg_mask(*oper);1237set_cisc_reg_mask_name(reg_mask_name);1238const char *stack_or_reg_mask_name = AD.stack_or_reg_mask(*oper);1239} else {1240cisc_spill_operand = Not_cisc_spillable;1241}1242} else {1243cisc_spill_operand = Not_cisc_spillable;1244}12451246set_cisc_spill_operand(cisc_spill_operand);1247return (cisc_spill_operand != Not_cisc_spillable);1248}12491250// Check to see if this instruction can be replaced with the short branch1251// instruction `short-branch'1252bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch) {1253if (_matrule != NULL &&1254this != short_branch && // Don't match myself1255!is_short_branch() && // Don't match another short branch variant1256reduce_result() != NULL &&1257strstr(_ident, "restoreMask") == NULL && // Don't match side effects1258strcmp(reduce_result(), short_branch->reduce_result()) == 0 &&1259_matrule->equivalent(AD.globalNames(), short_branch->_matrule)) {1260// The instructions are equivalent.12611262// Now verify that both instructions have the same parameters and1263// the same effects. Both branch forms should have the same inputs1264// and resulting projections to correctly replace a long branch node1265// with corresponding short branch node during code generation.12661267bool different = false;1268if (short_branch->_components.count() != _components.count()) {1269different = true;1270} else if (_components.count() > 0) {1271short_branch->_components.reset();1272_components.reset();1273Component *comp;1274while ((comp = _components.iter()) != NULL) {1275Component *short_comp = short_branch->_components.iter();1276if (short_comp == NULL ||1277short_comp->_type != comp->_type ||1278short_comp->_usedef != comp->_usedef) {1279different = true;1280break;1281}1282}1283if (short_branch->_components.iter() != NULL)1284different = true;1285}1286if (different) {1287globalAD->syntax_err(short_branch->_linenum, "Instruction %s and its short form %s have different parameters\n", _ident, short_branch->_ident);1288}1289if (AD._adl_debug > 1 || AD._short_branch_debug) {1290fprintf(stderr, "Instruction %s has short form %s\n", _ident, short_branch->_ident);1291}1292_short_branch_form = short_branch;1293return true;1294}1295return false;1296}129712981299// --------------------------- FILE *output_routines1300//1301// Generate the format call for the replacement variable1302void InstructForm::rep_var_format(FILE *fp, const char *rep_var) {1303// Handle special constant table variables.1304if (strcmp(rep_var, "constanttablebase") == 0) {1305fprintf(fp, "char reg[128]; ra->dump_register(in(mach_constant_base_node_input()), reg);\n");1306fprintf(fp, " st->print(\"%%s\", reg);\n");1307return;1308}1309if (strcmp(rep_var, "constantoffset") == 0) {1310fprintf(fp, "st->print(\"#%%d\", constant_offset_unchecked());\n");1311return;1312}1313if (strcmp(rep_var, "constantaddress") == 0) {1314fprintf(fp, "st->print(\"constant table base + #%%d\", constant_offset_unchecked());\n");1315return;1316}13171318// Find replacement variable's type1319const Form *form = _localNames[rep_var];1320if (form == NULL) {1321globalAD->syntax_err(_linenum, "Unknown replacement variable %s in format statement of %s.",1322rep_var, _ident);1323return;1324}1325OpClassForm *opc = form->is_opclass();1326assert( opc, "replacement variable was not found in local names");1327// Lookup the index position of the replacement variable1328int idx = operand_position_format(rep_var);1329if ( idx == -1 ) {1330globalAD->syntax_err(_linenum, "Could not find replacement variable %s in format statement of %s.\n",1331rep_var, _ident);1332assert(strcmp(opc->_ident, "label") == 0, "Unimplemented");1333return;1334}13351336if (is_noninput_operand(idx)) {1337// This component isn't in the input array. Print out the static1338// name of the register.1339OperandForm* oper = form->is_operand();1340if (oper != NULL && oper->is_bound_register()) {1341const RegDef* first = oper->get_RegClass()->find_first_elem();1342fprintf(fp, " st->print_raw(\"%s\");\n", first->_regname);1343} else {1344globalAD->syntax_err(_linenum, "In %s can't find format for %s %s", _ident, opc->_ident, rep_var);1345}1346} else {1347// Output the format call for this operand1348fprintf(fp,"opnd_array(%d)->",idx);1349if (idx == 0)1350fprintf(fp,"int_format(ra, this, st); // %s\n", rep_var);1351else1352fprintf(fp,"ext_format(ra, this,idx%d, st); // %s\n", idx, rep_var );1353}1354}13551356// Seach through operands to determine parameters unique positions.1357void InstructForm::set_unique_opnds() {1358uint* uniq_idx = NULL;1359uint nopnds = num_opnds();1360uint num_uniq = nopnds;1361uint i;1362_uniq_idx_length = 0;1363if (nopnds > 0) {1364// Allocate index array. Worst case we're mapping from each1365// component back to an index and any DEF always goes at 0 so the1366// length of the array has to be the number of components + 1.1367_uniq_idx_length = _components.count() + 1;1368uniq_idx = (uint*) AdlAllocateHeap(sizeof(uint) * _uniq_idx_length);1369for (i = 0; i < _uniq_idx_length; i++) {1370uniq_idx[i] = i;1371}1372}1373// Do it only if there is a match rule and no expand rule. With an1374// expand rule it is done by creating new mach node in Expand()1375// method.1376if (nopnds > 0 && _matrule != NULL && _exprule == NULL) {1377const char *name;1378uint count;1379bool has_dupl_use = false;13801381_parameters.reset();1382while ((name = _parameters.iter()) != NULL) {1383count = 0;1384uint position = 0;1385uint uniq_position = 0;1386_components.reset();1387Component *comp = NULL;1388if (sets_result()) {1389comp = _components.iter();1390position++;1391}1392// The next code is copied from the method operand_position().1393for (; (comp = _components.iter()) != NULL; ++position) {1394// When the first component is not a DEF,1395// leave space for the result operand!1396if (position==0 && (!comp->isa(Component::DEF))) {1397++position;1398}1399if (strcmp(name, comp->_name) == 0) {1400if (++count > 1) {1401assert(position < _uniq_idx_length, "out of bounds");1402uniq_idx[position] = uniq_position;1403has_dupl_use = true;1404} else {1405uniq_position = position;1406}1407}1408if (comp->isa(Component::DEF) && comp->isa(Component::USE)) {1409++position;1410if (position != 1)1411--position; // only use two slots for the 1st USE_DEF1412}1413}1414}1415if (has_dupl_use) {1416for (i = 1; i < nopnds; i++) {1417if (i != uniq_idx[i]) {1418break;1419}1420}1421uint j = i;1422for (; i < nopnds; i++) {1423if (i == uniq_idx[i]) {1424uniq_idx[i] = j++;1425}1426}1427num_uniq = j;1428}1429}1430_uniq_idx = uniq_idx;1431_num_uniq = num_uniq;1432}14331434// Generate index values needed for determining the operand position1435void InstructForm::index_temps(FILE *fp, FormDict &globals, const char *prefix, const char *receiver) {1436uint idx = 0; // position of operand in match rule1437int cur_num_opnds = num_opnds();14381439// Compute the index into vector of operand pointers:1440// idx0=0 is used to indicate that info comes from this same node, not from input edge.1441// idx1 starts at oper_input_base()1442if ( cur_num_opnds >= 1 ) {1443fprintf(fp," // Start at oper_input_base() and count operands\n");1444fprintf(fp," unsigned %sidx0 = %d;\n", prefix, oper_input_base(globals));1445fprintf(fp," unsigned %sidx1 = %d;", prefix, oper_input_base(globals));1446fprintf(fp," \t// %s\n", unique_opnd_ident(1));14471448// Generate starting points for other unique operands if they exist1449for ( idx = 2; idx < num_unique_opnds(); ++idx ) {1450if( *receiver == 0 ) {1451fprintf(fp," unsigned %sidx%d = %sidx%d + opnd_array(%d)->num_edges();",1452prefix, idx, prefix, idx-1, idx-1 );1453} else {1454fprintf(fp," unsigned %sidx%d = %sidx%d + %s_opnds[%d]->num_edges();",1455prefix, idx, prefix, idx-1, receiver, idx-1 );1456}1457fprintf(fp," \t// %s\n", unique_opnd_ident(idx));1458}1459}1460if( *receiver != 0 ) {1461// This value is used by generate_peepreplace when copying a node.1462// Don't emit it in other cases since it can hide bugs with the1463// use invalid idx's.1464fprintf(fp," unsigned %sidx%d = %sreq(); \n", prefix, idx, receiver);1465}14661467}14681469// ---------------------------1470bool InstructForm::verify() {1471// !!!!! !!!!!1472// Check that a "label" operand occurs last in the operand list, if present1473return true;1474}14751476void InstructForm::dump() {1477output(stderr);1478}14791480void InstructForm::output(FILE *fp) {1481fprintf(fp,"\nInstruction: %s\n", (_ident?_ident:""));1482if (_matrule) _matrule->output(fp);1483if (_insencode) _insencode->output(fp);1484if (_constant) _constant->output(fp);1485if (_opcode) _opcode->output(fp);1486if (_attribs) _attribs->output(fp);1487if (_predicate) _predicate->output(fp);1488if (_effects.Size()) {1489fprintf(fp,"Effects\n");1490_effects.dump();1491}1492if (_exprule) _exprule->output(fp);1493if (_rewrule) _rewrule->output(fp);1494if (_format) _format->output(fp);1495if (_peephole) _peephole->output(fp);1496}14971498void MachNodeForm::dump() {1499output(stderr);1500}15011502void MachNodeForm::output(FILE *fp) {1503fprintf(fp,"\nMachNode: %s\n", (_ident?_ident:""));1504}15051506//------------------------------build_predicate--------------------------------1507// Build instruction predicates. If the user uses the same operand name1508// twice, we need to check that the operands are pointer-eequivalent in1509// the DFA during the labeling process.1510Predicate *InstructForm::build_predicate() {1511const int buflen = 1024;1512char buf[buflen], *s=buf;1513Dict names(cmpstr,hashstr,Form::arena); // Map Names to counts15141515MatchNode *mnode =1516strcmp(_matrule->_opType, "Set") ? _matrule : _matrule->_rChild;1517if (mnode != NULL) mnode->count_instr_names(names);15181519uint first = 1;1520// Start with the predicate supplied in the .ad file.1521if (_predicate) {1522if (first) first = 0;1523strcpy(s, "("); s += strlen(s);1524strncpy(s, _predicate->_pred, buflen - strlen(s) - 1);1525s += strlen(s);1526strcpy(s, ")"); s += strlen(s);1527}1528for( DictI i(&names); i.test(); ++i ) {1529uintptr_t cnt = (uintptr_t)i._value;1530if( cnt > 1 ) { // Need a predicate at all?1531int path_bitmask = 0;1532assert( cnt == 2, "Unimplemented" );1533// Handle many pairs1534if( first ) first=0;1535else { // All tests must pass, so use '&&'1536strcpy(s," && ");1537s += strlen(s);1538}1539// Add predicate to working buffer1540sprintf(s,"/*%s*/(",(char*)i._key);1541s += strlen(s);1542mnode->build_instr_pred(s,(char*)i._key, 0, path_bitmask, 0);1543s += strlen(s);1544strcpy(s," == "); s += strlen(s);1545mnode->build_instr_pred(s,(char*)i._key, 1, path_bitmask, 0);1546s += strlen(s);1547strcpy(s,")"); s += strlen(s);1548}1549}1550if( s == buf ) s = NULL;1551else {1552assert( strlen(buf) < sizeof(buf), "String buffer overflow" );1553s = strdup(buf);1554}1555return new Predicate(s);1556}15571558//------------------------------EncodeForm-------------------------------------1559// Constructor1560EncodeForm::EncodeForm()1561: _encClass(cmpstr,hashstr, Form::arena) {1562}1563EncodeForm::~EncodeForm() {1564}15651566// record a new register class1567EncClass *EncodeForm::add_EncClass(const char *className) {1568EncClass *encClass = new EncClass(className);1569_eclasses.addName(className);1570_encClass.Insert(className,encClass);1571return encClass;1572}15731574// Lookup the function body for an encoding class1575EncClass *EncodeForm::encClass(const char *className) {1576assert( className != NULL, "Must provide a defined encoding name");15771578EncClass *encClass = (EncClass*)_encClass[className];1579return encClass;1580}15811582// Lookup the function body for an encoding class1583const char *EncodeForm::encClassBody(const char *className) {1584if( className == NULL ) return NULL;15851586EncClass *encClass = (EncClass*)_encClass[className];1587assert( encClass != NULL, "Encode Class is missing.");1588encClass->_code.reset();1589const char *code = (const char*)encClass->_code.iter();1590assert( code != NULL, "Found an empty encode class body.");15911592return code;1593}15941595// Lookup the function body for an encoding class1596const char *EncodeForm::encClassPrototype(const char *className) {1597assert( className != NULL, "Encode class name must be non NULL.");15981599return className;1600}16011602void EncodeForm::dump() { // Debug printer1603output(stderr);1604}16051606void EncodeForm::output(FILE *fp) { // Write info to output files1607const char *name;1608fprintf(fp,"\n");1609fprintf(fp,"-------------------- Dump EncodeForm --------------------\n");1610for (_eclasses.reset(); (name = _eclasses.iter()) != NULL;) {1611((EncClass*)_encClass[name])->output(fp);1612}1613fprintf(fp,"-------------------- end EncodeForm --------------------\n");1614}1615//------------------------------EncClass---------------------------------------1616EncClass::EncClass(const char *name)1617: _localNames(cmpstr,hashstr, Form::arena), _name(name) {1618}1619EncClass::~EncClass() {1620}16211622// Add a parameter <type,name> pair1623void EncClass::add_parameter(const char *parameter_type, const char *parameter_name) {1624_parameter_type.addName( parameter_type );1625_parameter_name.addName( parameter_name );1626}16271628// Verify operand types in parameter list1629bool EncClass::check_parameter_types(FormDict &globals) {1630// !!!!!1631return false;1632}16331634// Add the decomposed "code" sections of an encoding's code-block1635void EncClass::add_code(const char *code) {1636_code.addName(code);1637}16381639// Add the decomposed "replacement variables" of an encoding's code-block1640void EncClass::add_rep_var(char *replacement_var) {1641_code.addName(NameList::_signal);1642_rep_vars.addName(replacement_var);1643}16441645// Lookup the function body for an encoding class1646int EncClass::rep_var_index(const char *rep_var) {1647uint position = 0;1648const char *name = NULL;16491650_parameter_name.reset();1651while ( (name = _parameter_name.iter()) != NULL ) {1652if ( strcmp(rep_var,name) == 0 ) return position;1653++position;1654}16551656return -1;1657}16581659// Check after parsing1660bool EncClass::verify() {1661// 1!!!!1662// Check that each replacement variable, '$name' in architecture description1663// is actually a local variable for this encode class, or a reserved name1664// "primary, secondary, tertiary"1665return true;1666}16671668void EncClass::dump() {1669output(stderr);1670}16711672// Write info to output files1673void EncClass::output(FILE *fp) {1674fprintf(fp,"EncClass: %s", (_name ? _name : ""));16751676// Output the parameter list1677_parameter_type.reset();1678_parameter_name.reset();1679const char *type = _parameter_type.iter();1680const char *name = _parameter_name.iter();1681fprintf(fp, " ( ");1682for ( ; (type != NULL) && (name != NULL);1683(type = _parameter_type.iter()), (name = _parameter_name.iter()) ) {1684fprintf(fp, " %s %s,", type, name);1685}1686fprintf(fp, " ) ");16871688// Output the code block1689_code.reset();1690_rep_vars.reset();1691const char *code;1692while ( (code = _code.iter()) != NULL ) {1693if ( _code.is_signal(code) ) {1694// A replacement variable1695const char *rep_var = _rep_vars.iter();1696fprintf(fp,"($%s)", rep_var);1697} else {1698// A section of code1699fprintf(fp,"%s", code);1700}1701}17021703}17041705//------------------------------Opcode-----------------------------------------1706Opcode::Opcode(char *primary, char *secondary, char *tertiary)1707: _primary(primary), _secondary(secondary), _tertiary(tertiary) {1708}17091710Opcode::~Opcode() {1711}17121713Opcode::opcode_type Opcode::as_opcode_type(const char *param) {1714if( strcmp(param,"primary") == 0 ) {1715return Opcode::PRIMARY;1716}1717else if( strcmp(param,"secondary") == 0 ) {1718return Opcode::SECONDARY;1719}1720else if( strcmp(param,"tertiary") == 0 ) {1721return Opcode::TERTIARY;1722}1723return Opcode::NOT_AN_OPCODE;1724}17251726bool Opcode::print_opcode(FILE *fp, Opcode::opcode_type desired_opcode) {1727// Default values previously provided by MachNode::primary()...1728const char *description = NULL;1729const char *value = NULL;1730// Check if user provided any opcode definitions1731// Update 'value' if user provided a definition in the instruction1732switch (desired_opcode) {1733case PRIMARY:1734description = "primary()";1735if( _primary != NULL) { value = _primary; }1736break;1737case SECONDARY:1738description = "secondary()";1739if( _secondary != NULL ) { value = _secondary; }1740break;1741case TERTIARY:1742description = "tertiary()";1743if( _tertiary != NULL ) { value = _tertiary; }1744break;1745default:1746assert( false, "ShouldNotReachHere();");1747break;1748}17491750if (value != NULL) {1751fprintf(fp, "(%s /*%s*/)", value, description);1752}1753return value != NULL;1754}17551756void Opcode::dump() {1757output(stderr);1758}17591760// Write info to output files1761void Opcode::output(FILE *fp) {1762if (_primary != NULL) fprintf(fp,"Primary opcode: %s\n", _primary);1763if (_secondary != NULL) fprintf(fp,"Secondary opcode: %s\n", _secondary);1764if (_tertiary != NULL) fprintf(fp,"Tertiary opcode: %s\n", _tertiary);1765}17661767//------------------------------InsEncode--------------------------------------1768InsEncode::InsEncode() {1769}1770InsEncode::~InsEncode() {1771}17721773// Add "encode class name" and its parameters1774NameAndList *InsEncode::add_encode(char *encoding) {1775assert( encoding != NULL, "Must provide name for encoding");17761777// add_parameter(NameList::_signal);1778NameAndList *encode = new NameAndList(encoding);1779_encoding.addName((char*)encode);17801781return encode;1782}17831784// Access the list of encodings1785void InsEncode::reset() {1786_encoding.reset();1787// _parameter.reset();1788}1789const char* InsEncode::encode_class_iter() {1790NameAndList *encode_class = (NameAndList*)_encoding.iter();1791return ( encode_class != NULL ? encode_class->name() : NULL );1792}1793// Obtain parameter name from zero based index1794const char *InsEncode::rep_var_name(InstructForm &inst, uint param_no) {1795NameAndList *params = (NameAndList*)_encoding.current();1796assert( params != NULL, "Internal Error");1797const char *param = (*params)[param_no];17981799// Remove '$' if parser placed it there.1800return ( param != NULL && *param == '$') ? (param+1) : param;1801}18021803void InsEncode::dump() {1804output(stderr);1805}18061807// Write info to output files1808void InsEncode::output(FILE *fp) {1809NameAndList *encoding = NULL;1810const char *parameter = NULL;18111812fprintf(fp,"InsEncode: ");1813_encoding.reset();18141815while ( (encoding = (NameAndList*)_encoding.iter()) != 0 ) {1816// Output the encoding being used1817fprintf(fp,"%s(", encoding->name() );18181819// Output its parameter list, if any1820bool first_param = true;1821encoding->reset();1822while ( (parameter = encoding->iter()) != 0 ) {1823// Output the ',' between parameters1824if ( ! first_param ) fprintf(fp,", ");1825first_param = false;1826// Output the parameter1827fprintf(fp,"%s", parameter);1828} // done with parameters1829fprintf(fp,") ");1830} // done with encodings18311832fprintf(fp,"\n");1833}18341835//------------------------------Effect-----------------------------------------1836static int effect_lookup(const char *name) {1837if (!strcmp(name, "USE")) return Component::USE;1838if (!strcmp(name, "DEF")) return Component::DEF;1839if (!strcmp(name, "USE_DEF")) return Component::USE_DEF;1840if (!strcmp(name, "KILL")) return Component::KILL;1841if (!strcmp(name, "USE_KILL")) return Component::USE_KILL;1842if (!strcmp(name, "TEMP")) return Component::TEMP;1843if (!strcmp(name, "TEMP_DEF")) return Component::TEMP_DEF;1844if (!strcmp(name, "INVALID")) return Component::INVALID;1845if (!strcmp(name, "CALL")) return Component::CALL;1846assert(false,"Invalid effect name specified\n");1847return Component::INVALID;1848}18491850const char *Component::getUsedefName() {1851switch (_usedef) {1852case Component::INVALID: return "INVALID"; break;1853case Component::USE: return "USE"; break;1854case Component::USE_DEF: return "USE_DEF"; break;1855case Component::USE_KILL: return "USE_KILL"; break;1856case Component::KILL: return "KILL"; break;1857case Component::TEMP: return "TEMP"; break;1858case Component::TEMP_DEF: return "TEMP_DEF"; break;1859case Component::DEF: return "DEF"; break;1860case Component::CALL: return "CALL"; break;1861default: assert(false, "unknown effect");1862}1863return "Undefined Use/Def info";1864}18651866Effect::Effect(const char *name) : _name(name), _use_def(effect_lookup(name)) {1867_ftype = Form::EFF;1868}18691870Effect::~Effect() {1871}18721873// Dynamic type check1874Effect *Effect::is_effect() const {1875return (Effect*)this;1876}187718781879// True if this component is equal to the parameter.1880bool Effect::is(int use_def_kill_enum) const {1881return (_use_def == use_def_kill_enum ? true : false);1882}1883// True if this component is used/def'd/kill'd as the parameter suggests.1884bool Effect::isa(int use_def_kill_enum) const {1885return (_use_def & use_def_kill_enum) == use_def_kill_enum;1886}18871888void Effect::dump() {1889output(stderr);1890}18911892void Effect::output(FILE *fp) { // Write info to output files1893fprintf(fp,"Effect: %s\n", (_name?_name:""));1894}18951896//------------------------------ExpandRule-------------------------------------1897ExpandRule::ExpandRule() : _expand_instrs(),1898_newopconst(cmpstr, hashstr, Form::arena) {1899_ftype = Form::EXP;1900}19011902ExpandRule::~ExpandRule() { // Destructor1903}19041905void ExpandRule::add_instruction(NameAndList *instruction_name_and_operand_list) {1906_expand_instrs.addName((char*)instruction_name_and_operand_list);1907}19081909void ExpandRule::reset_instructions() {1910_expand_instrs.reset();1911}19121913NameAndList* ExpandRule::iter_instructions() {1914return (NameAndList*)_expand_instrs.iter();1915}191619171918void ExpandRule::dump() {1919output(stderr);1920}19211922void ExpandRule::output(FILE *fp) { // Write info to output files1923NameAndList *expand_instr = NULL;1924const char *opid = NULL;19251926fprintf(fp,"\nExpand Rule:\n");19271928// Iterate over the instructions 'node' expands into1929for(reset_instructions(); (expand_instr = iter_instructions()) != NULL; ) {1930fprintf(fp,"%s(", expand_instr->name());19311932// iterate over the operand list1933for( expand_instr->reset(); (opid = expand_instr->iter()) != NULL; ) {1934fprintf(fp,"%s ", opid);1935}1936fprintf(fp,");\n");1937}1938}19391940//------------------------------RewriteRule------------------------------------1941RewriteRule::RewriteRule(char* params, char* block)1942: _tempParams(params), _tempBlock(block) { }; // Constructor1943RewriteRule::~RewriteRule() { // Destructor1944}19451946void RewriteRule::dump() {1947output(stderr);1948}19491950void RewriteRule::output(FILE *fp) { // Write info to output files1951fprintf(fp,"\nRewrite Rule:\n%s\n%s\n",1952(_tempParams?_tempParams:""),1953(_tempBlock?_tempBlock:""));1954}195519561957//==============================MachNodes======================================1958//------------------------------MachNodeForm-----------------------------------1959MachNodeForm::MachNodeForm(char *id)1960: _ident(id) {1961}19621963MachNodeForm::~MachNodeForm() {1964}19651966MachNodeForm *MachNodeForm::is_machnode() const {1967return (MachNodeForm*)this;1968}19691970//==============================Operand Classes================================1971//------------------------------OpClassForm------------------------------------1972OpClassForm::OpClassForm(const char* id) : _ident(id) {1973_ftype = Form::OPCLASS;1974}19751976OpClassForm::~OpClassForm() {1977}19781979bool OpClassForm::ideal_only() const { return 0; }19801981OpClassForm *OpClassForm::is_opclass() const {1982return (OpClassForm*)this;1983}19841985Form::InterfaceType OpClassForm::interface_type(FormDict &globals) const {1986if( _oplst.count() == 0 ) return Form::no_interface;19871988// Check that my operands have the same interface type1989Form::InterfaceType interface;1990bool first = true;1991NameList &op_list = (NameList &)_oplst;1992op_list.reset();1993const char *op_name;1994while( (op_name = op_list.iter()) != NULL ) {1995const Form *form = globals[op_name];1996OperandForm *operand = form->is_operand();1997assert( operand, "Entry in operand class that is not an operand");1998if( first ) {1999first = false;2000interface = operand->interface_type(globals);2001} else {2002interface = (interface == operand->interface_type(globals) ? interface : Form::no_interface);2003}2004}2005return interface;2006}20072008bool OpClassForm::stack_slots_only(FormDict &globals) const {2009if( _oplst.count() == 0 ) return false; // how?20102011NameList &op_list = (NameList &)_oplst;2012op_list.reset();2013const char *op_name;2014while( (op_name = op_list.iter()) != NULL ) {2015const Form *form = globals[op_name];2016OperandForm *operand = form->is_operand();2017assert( operand, "Entry in operand class that is not an operand");2018if( !operand->stack_slots_only(globals) ) return false;2019}2020return true;2021}202220232024void OpClassForm::dump() {2025output(stderr);2026}20272028void OpClassForm::output(FILE *fp) {2029const char *name;2030fprintf(fp,"\nOperand Class: %s\n", (_ident?_ident:""));2031fprintf(fp,"\nCount = %d\n", _oplst.count());2032for(_oplst.reset(); (name = _oplst.iter()) != NULL;) {2033fprintf(fp,"%s, ",name);2034}2035fprintf(fp,"\n");2036}203720382039//==============================Operands=======================================2040//------------------------------OperandForm------------------------------------2041OperandForm::OperandForm(const char* id)2042: OpClassForm(id), _ideal_only(false),2043_localNames(cmpstr, hashstr, Form::arena) {2044_ftype = Form::OPER;20452046_matrule = NULL;2047_interface = NULL;2048_attribs = NULL;2049_predicate = NULL;2050_constraint= NULL;2051_construct = NULL;2052_format = NULL;2053}2054OperandForm::OperandForm(const char* id, bool ideal_only)2055: OpClassForm(id), _ideal_only(ideal_only),2056_localNames(cmpstr, hashstr, Form::arena) {2057_ftype = Form::OPER;20582059_matrule = NULL;2060_interface = NULL;2061_attribs = NULL;2062_predicate = NULL;2063_constraint= NULL;2064_construct = NULL;2065_format = NULL;2066}2067OperandForm::~OperandForm() {2068}206920702071OperandForm *OperandForm::is_operand() const {2072return (OperandForm*)this;2073}20742075bool OperandForm::ideal_only() const {2076return _ideal_only;2077}20782079Form::InterfaceType OperandForm::interface_type(FormDict &globals) const {2080if( _interface == NULL ) return Form::no_interface;20812082return _interface->interface_type(globals);2083}208420852086bool OperandForm::stack_slots_only(FormDict &globals) const {2087if( _constraint == NULL ) return false;2088return _constraint->stack_slots_only();2089}209020912092// Access op_cost attribute or return NULL.2093const char* OperandForm::cost() {2094for (Attribute* cur = _attribs; cur != NULL; cur = (Attribute*)cur->_next) {2095if( strcmp(cur->_ident,AttributeForm::_op_cost) == 0 ) {2096return cur->_val;2097}2098}2099return NULL;2100}21012102// Return the number of leaves below this complex operand2103uint OperandForm::num_leaves() const {2104if ( ! _matrule) return 0;21052106int num_leaves = _matrule->_numleaves;2107return num_leaves;2108}21092110// Return the number of constants contained within this complex operand2111uint OperandForm::num_consts(FormDict &globals) const {2112if ( ! _matrule) return 0;21132114// This is a recursive invocation on all operands in the matchrule2115return _matrule->num_consts(globals);2116}21172118// Return the number of constants in match rule with specified type2119uint OperandForm::num_consts(FormDict &globals, Form::DataType type) const {2120if ( ! _matrule) return 0;21212122// This is a recursive invocation on all operands in the matchrule2123return _matrule->num_consts(globals, type);2124}21252126// Return the number of pointer constants contained within this complex operand2127uint OperandForm::num_const_ptrs(FormDict &globals) const {2128if ( ! _matrule) return 0;21292130// This is a recursive invocation on all operands in the matchrule2131return _matrule->num_const_ptrs(globals);2132}21332134uint OperandForm::num_edges(FormDict &globals) const {2135uint edges = 0;2136uint leaves = num_leaves();2137uint consts = num_consts(globals);21382139// If we are matching a constant directly, there are no leaves.2140edges = ( leaves > consts ) ? leaves - consts : 0;21412142// !!!!!2143// Special case operands that do not have a corresponding ideal node.2144if( (edges == 0) && (consts == 0) ) {2145if( constrained_reg_class() != NULL ) {2146edges = 1;2147} else {2148if( _matrule2149&& (_matrule->_lChild == NULL) && (_matrule->_rChild == NULL) ) {2150const Form *form = globals[_matrule->_opType];2151OperandForm *oper = form ? form->is_operand() : NULL;2152if( oper ) {2153return oper->num_edges(globals);2154}2155}2156}2157}21582159return edges;2160}216121622163// Check if this operand is usable for cisc-spilling2164bool OperandForm::is_cisc_reg(FormDict &globals) const {2165const char *ideal = ideal_type(globals);2166bool is_cisc_reg = (ideal && (ideal_to_Reg_type(ideal) != none));2167return is_cisc_reg;2168}21692170bool OpClassForm::is_cisc_mem(FormDict &globals) const {2171Form::InterfaceType my_interface = interface_type(globals);2172return (my_interface == memory_interface);2173}217421752176// node matches ideal 'Bool'2177bool OperandForm::is_ideal_bool() const {2178if( _matrule == NULL ) return false;21792180return _matrule->is_ideal_bool();2181}21822183// Require user's name for an sRegX to be stackSlotX2184Form::DataType OperandForm::is_user_name_for_sReg() const {2185DataType data_type = none;2186if( _ident != NULL ) {2187if( strcmp(_ident,"stackSlotI") == 0 ) data_type = Form::idealI;2188else if( strcmp(_ident,"stackSlotP") == 0 ) data_type = Form::idealP;2189else if( strcmp(_ident,"stackSlotD") == 0 ) data_type = Form::idealD;2190else if( strcmp(_ident,"stackSlotF") == 0 ) data_type = Form::idealF;2191else if( strcmp(_ident,"stackSlotL") == 0 ) data_type = Form::idealL;2192}2193assert((data_type == none) || (_matrule == NULL), "No match-rule for stackSlotX");21942195return data_type;2196}219721982199// Return ideal type, if there is a single ideal type for this operand2200const char *OperandForm::ideal_type(FormDict &globals, RegisterForm *registers) const {2201const char *type = NULL;2202if (ideal_only()) type = _ident;2203else if( _matrule == NULL ) {2204// Check for condition code register2205const char *rc_name = constrained_reg_class();2206// !!!!!2207if (rc_name == NULL) return NULL;2208// !!!!! !!!!!2209// Check constraints on result's register class2210if( registers ) {2211RegClass *reg_class = registers->getRegClass(rc_name);2212assert( reg_class != NULL, "Register class is not defined");22132214// Check for ideal type of entries in register class, all are the same type2215reg_class->reset();2216RegDef *reg_def = reg_class->RegDef_iter();2217assert( reg_def != NULL, "No entries in register class");2218assert( reg_def->_idealtype != NULL, "Did not define ideal type for register");2219// Return substring that names the register's ideal type2220type = reg_def->_idealtype + 3;2221assert( *(reg_def->_idealtype + 0) == 'O', "Expect Op_ prefix");2222assert( *(reg_def->_idealtype + 1) == 'p', "Expect Op_ prefix");2223assert( *(reg_def->_idealtype + 2) == '_', "Expect Op_ prefix");2224}2225}2226else if( _matrule->_lChild == NULL && _matrule->_rChild == NULL ) {2227// This operand matches a single type, at the top level.2228// Check for ideal type2229type = _matrule->_opType;2230if( strcmp(type,"Bool") == 0 )2231return "Bool";2232// transitive lookup2233const Form *frm = globals[type];2234OperandForm *op = frm->is_operand();2235type = op->ideal_type(globals, registers);2236}2237return type;2238}223922402241// If there is a single ideal type for this interface field, return it.2242const char *OperandForm::interface_ideal_type(FormDict &globals,2243const char *field) const {2244const char *ideal_type = NULL;2245const char *value = NULL;22462247// Check if "field" is valid for this operand's interface2248if ( ! is_interface_field(field, value) ) return ideal_type;22492250// !!!!! !!!!! !!!!!2251// If a valid field has a constant value, identify "ConI" or "ConP" or ...22522253// Else, lookup type of field's replacement variable22542255return ideal_type;2256}225722582259RegClass* OperandForm::get_RegClass() const {2260if (_interface && !_interface->is_RegInterface()) return NULL;2261return globalAD->get_registers()->getRegClass(constrained_reg_class());2262}226322642265bool OperandForm::is_bound_register() const {2266RegClass* reg_class = get_RegClass();2267if (reg_class == NULL) {2268return false;2269}22702271const char* name = ideal_type(globalAD->globalNames());2272if (name == NULL) {2273return false;2274}22752276uint size = 0;2277if (strcmp(name, "RegFlags") == 0) size = 1;2278if (strcmp(name, "RegI") == 0) size = 1;2279if (strcmp(name, "RegF") == 0) size = 1;2280if (strcmp(name, "RegD") == 0) size = 2;2281if (strcmp(name, "RegL") == 0) size = 2;2282if (strcmp(name, "RegN") == 0) size = 1;2283if (strcmp(name, "VecX") == 0) size = 4;2284if (strcmp(name, "VecY") == 0) size = 8;2285if (strcmp(name, "VecZ") == 0) size = 16;2286if (strcmp(name, "RegP") == 0) size = globalAD->get_preproc_def("_LP64") ? 2 : 1;2287if (size == 0) {2288return false;2289}2290return size == reg_class->size();2291}229222932294// Check if this is a valid field for this operand,2295// Return 'true' if valid, and set the value to the string the user provided.2296bool OperandForm::is_interface_field(const char *field,2297const char * &value) const {2298return false;2299}230023012302// Return register class name if a constraint specifies the register class.2303const char *OperandForm::constrained_reg_class() const {2304const char *reg_class = NULL;2305if ( _constraint ) {2306// !!!!!2307Constraint *constraint = _constraint;2308if ( strcmp(_constraint->_func,"ALLOC_IN_RC") == 0 ) {2309reg_class = _constraint->_arg;2310}2311}23122313return reg_class;2314}231523162317// Return the register class associated with 'leaf'.2318const char *OperandForm::in_reg_class(uint leaf, FormDict &globals) {2319const char *reg_class = NULL; // "RegMask::Empty";23202321if((_matrule == NULL) || (_matrule->is_chain_rule(globals))) {2322reg_class = constrained_reg_class();2323return reg_class;2324}2325const char *result = NULL;2326const char *name = NULL;2327const char *type = NULL;2328// iterate through all base operands2329// until we reach the register that corresponds to "leaf"2330// This function is not looking for an ideal type. It needs the first2331// level user type associated with the leaf.2332for(uint idx = 0;_matrule->base_operand(idx,globals,result,name,type);++idx) {2333const Form *form = (_localNames[name] ? _localNames[name] : globals[result]);2334OperandForm *oper = form ? form->is_operand() : NULL;2335if( oper ) {2336reg_class = oper->constrained_reg_class();2337if( reg_class ) {2338reg_class = reg_class;2339} else {2340// ShouldNotReachHere();2341}2342} else {2343// ShouldNotReachHere();2344}23452346// Increment our target leaf position if current leaf is not a candidate.2347if( reg_class == NULL) ++leaf;2348// Exit the loop with the value of reg_class when at the correct index2349if( idx == leaf ) break;2350// May iterate through all base operands if reg_class for 'leaf' is NULL2351}2352return reg_class;2353}235423552356// Recursive call to construct list of top-level operands.2357// Implementation does not modify state of internal structures2358void OperandForm::build_components() {2359if (_matrule) _matrule->append_components(_localNames, _components);23602361// Add parameters that "do not appear in match rule".2362const char *name;2363for (_parameters.reset(); (name = _parameters.iter()) != NULL;) {2364OpClassForm *opForm = _localNames[name]->is_opclass();2365assert(opForm != NULL, "sanity");23662367if ( _components.operand_position(name) == -1 ) {2368_components.insert(name, opForm->_ident, Component::INVALID, false);2369}2370}23712372return;2373}23742375int OperandForm::operand_position(const char *name, int usedef) {2376return _components.operand_position(name, usedef, this);2377}237823792380// Return zero-based position in component list, only counting constants;2381// Return -1 if not in list.2382int OperandForm::constant_position(FormDict &globals, const Component *last) {2383// Iterate through components and count constants preceding 'constant'2384int position = 0;2385Component *comp;2386_components.reset();2387while( (comp = _components.iter()) != NULL && (comp != last) ) {2388// Special case for operands that take a single user-defined operand2389// Skip the initial definition in the component list.2390if( strcmp(comp->_name,this->_ident) == 0 ) continue;23912392const char *type = comp->_type;2393// Lookup operand form for replacement variable's type2394const Form *form = globals[type];2395assert( form != NULL, "Component's type not found");2396OperandForm *oper = form ? form->is_operand() : NULL;2397if( oper ) {2398if( oper->_matrule->is_base_constant(globals) != Form::none ) {2399++position;2400}2401}2402}24032404// Check for being passed a component that was not in the list2405if( comp != last ) position = -1;24062407return position;2408}2409// Provide position of constant by "name"2410int OperandForm::constant_position(FormDict &globals, const char *name) {2411const Component *comp = _components.search(name);2412int idx = constant_position( globals, comp );24132414return idx;2415}241624172418// Return zero-based position in component list, only counting constants;2419// Return -1 if not in list.2420int OperandForm::register_position(FormDict &globals, const char *reg_name) {2421// Iterate through components and count registers preceding 'last'2422uint position = 0;2423Component *comp;2424_components.reset();2425while( (comp = _components.iter()) != NULL2426&& (strcmp(comp->_name,reg_name) != 0) ) {2427// Special case for operands that take a single user-defined operand2428// Skip the initial definition in the component list.2429if( strcmp(comp->_name,this->_ident) == 0 ) continue;24302431const char *type = comp->_type;2432// Lookup operand form for component's type2433const Form *form = globals[type];2434assert( form != NULL, "Component's type not found");2435OperandForm *oper = form ? form->is_operand() : NULL;2436if( oper ) {2437if( oper->_matrule->is_base_register(globals) ) {2438++position;2439}2440}2441}24422443return position;2444}244524462447const char *OperandForm::reduce_result() const {2448return _ident;2449}2450// Return the name of the operand on the right hand side of the binary match2451// Return NULL if there is no right hand side2452const char *OperandForm::reduce_right(FormDict &globals) const {2453return ( _matrule ? _matrule->reduce_right(globals) : NULL );2454}24552456// Similar for left2457const char *OperandForm::reduce_left(FormDict &globals) const {2458return ( _matrule ? _matrule->reduce_left(globals) : NULL );2459}246024612462// --------------------------- FILE *output_routines2463//2464// Output code for disp_is_oop, if true.2465void OperandForm::disp_is_oop(FILE *fp, FormDict &globals) {2466// Check it is a memory interface with a non-user-constant disp field2467if ( this->_interface == NULL ) return;2468MemInterface *mem_interface = this->_interface->is_MemInterface();2469if ( mem_interface == NULL ) return;2470const char *disp = mem_interface->_disp;2471if ( *disp != '$' ) return;24722473// Lookup replacement variable in operand's component list2474const char *rep_var = disp + 1;2475const Component *comp = this->_components.search(rep_var);2476assert( comp != NULL, "Replacement variable not found in components");2477// Lookup operand form for replacement variable's type2478const char *type = comp->_type;2479Form *form = (Form*)globals[type];2480assert( form != NULL, "Replacement variable's type not found");2481OperandForm *op = form->is_operand();2482assert( op, "Memory Interface 'disp' can only emit an operand form");2483// Check if this is a ConP, which may require relocation2484if ( op->is_base_constant(globals) == Form::idealP ) {2485// Find the constant's index: _c0, _c1, _c2, ... , _cN2486uint idx = op->constant_position( globals, rep_var);2487fprintf(fp," virtual relocInfo::relocType disp_reloc() const {");2488fprintf(fp, " return _c%d->reloc();", idx);2489fprintf(fp, " }\n");2490}2491}24922493// Generate code for internal and external format methods2494//2495// internal access to reg# node->_idx2496// access to subsumed constant _c0, _c1,2497void OperandForm::int_format(FILE *fp, FormDict &globals, uint index) {2498Form::DataType dtype;2499if (_matrule && (_matrule->is_base_register(globals) ||2500strcmp(ideal_type(globalAD->globalNames()), "RegFlags") == 0)) {2501// !!!!! !!!!!2502fprintf(fp," { char reg_str[128];\n");2503fprintf(fp," ra->dump_register(node,reg_str);\n");2504fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2505fprintf(fp," }\n");2506} else if (_matrule && (dtype = _matrule->is_base_constant(globals)) != Form::none) {2507format_constant( fp, index, dtype );2508} else if (ideal_to_sReg_type(_ident) != Form::none) {2509// Special format for Stack Slot Register2510fprintf(fp," { char reg_str[128];\n");2511fprintf(fp," ra->dump_register(node,reg_str);\n");2512fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2513fprintf(fp," }\n");2514} else {2515fprintf(fp," st->print(\"No format defined for %s\n\");\n", _ident);2516fflush(fp);2517fprintf(stderr,"No format defined for %s\n", _ident);2518dump();2519assert( false,"Internal error:\n output_internal_operand() attempting to output other than a Register or Constant");2520}2521}25222523// Similar to "int_format" but for cases where data is external to operand2524// external access to reg# node->in(idx)->_idx,2525void OperandForm::ext_format(FILE *fp, FormDict &globals, uint index) {2526Form::DataType dtype;2527if (_matrule && (_matrule->is_base_register(globals) ||2528strcmp(ideal_type(globalAD->globalNames()), "RegFlags") == 0)) {2529fprintf(fp," { char reg_str[128];\n");2530fprintf(fp," ra->dump_register(node->in(idx");2531if ( index != 0 ) fprintf(fp, "+%d",index);2532fprintf(fp, "),reg_str);\n");2533fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2534fprintf(fp," }\n");2535} else if (_matrule && (dtype = _matrule->is_base_constant(globals)) != Form::none) {2536format_constant( fp, index, dtype );2537} else if (ideal_to_sReg_type(_ident) != Form::none) {2538// Special format for Stack Slot Register2539fprintf(fp," { char reg_str[128];\n");2540fprintf(fp," ra->dump_register(node->in(idx");2541if ( index != 0 ) fprintf(fp, "+%d",index);2542fprintf(fp, "),reg_str);\n");2543fprintf(fp," st->print(\"%cs\",reg_str);\n",'%');2544fprintf(fp," }\n");2545} else {2546fprintf(fp," st->print(\"No format defined for %s\n\");\n", _ident);2547assert( false,"Internal error:\n output_external_operand() attempting to output other than a Register or Constant");2548}2549}25502551void OperandForm::format_constant(FILE *fp, uint const_index, uint const_type) {2552switch(const_type) {2553case Form::idealI: fprintf(fp," st->print(\"#%%d\", _c%d);\n", const_index); break;2554case Form::idealP: fprintf(fp," if (_c%d) _c%d->dump_on(st);\n", const_index, const_index); break;2555case Form::idealNKlass:2556case Form::idealN: fprintf(fp," if (_c%d) _c%d->dump_on(st);\n", const_index, const_index); break;2557case Form::idealL: fprintf(fp," st->print(\"#\" INT64_FORMAT, (int64_t)_c%d);\n", const_index); break;2558case Form::idealF: fprintf(fp," st->print(\"#%%f\", _c%d);\n", const_index); break;2559case Form::idealD: fprintf(fp," st->print(\"#%%f\", _c%d);\n", const_index); break;2560default:2561assert( false, "ShouldNotReachHere()");2562}2563}25642565// Return the operand form corresponding to the given index, else NULL.2566OperandForm *OperandForm::constant_operand(FormDict &globals,2567uint index) {2568// !!!!!2569// Check behavior on complex operands2570uint n_consts = num_consts(globals);2571if( n_consts > 0 ) {2572uint i = 0;2573const char *type;2574Component *comp;2575_components.reset();2576if ((comp = _components.iter()) == NULL) {2577assert(n_consts == 1, "Bad component list detected.\n");2578// Current operand is THE operand2579if ( index == 0 ) {2580return this;2581}2582} // end if NULL2583else {2584// Skip the first component, it can not be a DEF of a constant2585do {2586type = comp->base_type(globals);2587// Check that "type" is a 'ConI', 'ConP', ...2588if ( ideal_to_const_type(type) != Form::none ) {2589// When at correct component, get corresponding Operand2590if ( index == 0 ) {2591return globals[comp->_type]->is_operand();2592}2593// Decrement number of constants to go2594--index;2595}2596} while((comp = _components.iter()) != NULL);2597}2598}25992600// Did not find a constant for this index.2601return NULL;2602}26032604// If this operand has a single ideal type, return its type2605Form::DataType OperandForm::simple_type(FormDict &globals) const {2606const char *type_name = ideal_type(globals);2607Form::DataType type = type_name ? ideal_to_const_type( type_name )2608: Form::none;2609return type;2610}26112612Form::DataType OperandForm::is_base_constant(FormDict &globals) const {2613if ( _matrule == NULL ) return Form::none;26142615return _matrule->is_base_constant(globals);2616}26172618// "true" if this operand is a simple type that is swallowed2619bool OperandForm::swallowed(FormDict &globals) const {2620Form::DataType type = simple_type(globals);2621if( type != Form::none ) {2622return true;2623}26242625return false;2626}26272628// Output code to access the value of the index'th constant2629void OperandForm::access_constant(FILE *fp, FormDict &globals,2630uint const_index) {2631OperandForm *oper = constant_operand(globals, const_index);2632assert( oper, "Index exceeds number of constants in operand");2633Form::DataType dtype = oper->is_base_constant(globals);26342635switch(dtype) {2636case idealI: fprintf(fp,"_c%d", const_index); break;2637case idealP: fprintf(fp,"_c%d->get_con()",const_index); break;2638case idealL: fprintf(fp,"_c%d", const_index); break;2639case idealF: fprintf(fp,"_c%d", const_index); break;2640case idealD: fprintf(fp,"_c%d", const_index); break;2641default:2642assert( false, "ShouldNotReachHere()");2643}2644}264526462647void OperandForm::dump() {2648output(stderr);2649}26502651void OperandForm::output(FILE *fp) {2652fprintf(fp,"\nOperand: %s\n", (_ident?_ident:""));2653if (_matrule) _matrule->dump();2654if (_interface) _interface->dump();2655if (_attribs) _attribs->dump();2656if (_predicate) _predicate->dump();2657if (_constraint) _constraint->dump();2658if (_construct) _construct->dump();2659if (_format) _format->dump();2660}26612662//------------------------------Constraint-------------------------------------2663Constraint::Constraint(const char *func, const char *arg)2664: _func(func), _arg(arg) {2665}2666Constraint::~Constraint() { /* not owner of char* */2667}26682669bool Constraint::stack_slots_only() const {2670return strcmp(_func, "ALLOC_IN_RC") == 02671&& strcmp(_arg, "stack_slots") == 0;2672}26732674void Constraint::dump() {2675output(stderr);2676}26772678void Constraint::output(FILE *fp) { // Write info to output files2679assert((_func != NULL && _arg != NULL),"missing constraint function or arg");2680fprintf(fp,"Constraint: %s ( %s )\n", _func, _arg);2681}26822683//------------------------------Predicate--------------------------------------2684Predicate::Predicate(char *pr)2685: _pred(pr) {2686}2687Predicate::~Predicate() {2688}26892690void Predicate::dump() {2691output(stderr);2692}26932694void Predicate::output(FILE *fp) {2695fprintf(fp,"Predicate"); // Write to output files2696}2697//------------------------------Interface--------------------------------------2698Interface::Interface(const char *name) : _name(name) {2699}2700Interface::~Interface() {2701}27022703Form::InterfaceType Interface::interface_type(FormDict &globals) const {2704Interface *thsi = (Interface*)this;2705if ( thsi->is_RegInterface() ) return Form::register_interface;2706if ( thsi->is_MemInterface() ) return Form::memory_interface;2707if ( thsi->is_ConstInterface() ) return Form::constant_interface;2708if ( thsi->is_CondInterface() ) return Form::conditional_interface;27092710return Form::no_interface;2711}27122713RegInterface *Interface::is_RegInterface() {2714if ( strcmp(_name,"REG_INTER") != 0 )2715return NULL;2716return (RegInterface*)this;2717}2718MemInterface *Interface::is_MemInterface() {2719if ( strcmp(_name,"MEMORY_INTER") != 0 ) return NULL;2720return (MemInterface*)this;2721}2722ConstInterface *Interface::is_ConstInterface() {2723if ( strcmp(_name,"CONST_INTER") != 0 ) return NULL;2724return (ConstInterface*)this;2725}2726CondInterface *Interface::is_CondInterface() {2727if ( strcmp(_name,"COND_INTER") != 0 ) return NULL;2728return (CondInterface*)this;2729}273027312732void Interface::dump() {2733output(stderr);2734}27352736// Write info to output files2737void Interface::output(FILE *fp) {2738fprintf(fp,"Interface: %s\n", (_name ? _name : "") );2739}27402741//------------------------------RegInterface-----------------------------------2742RegInterface::RegInterface() : Interface("REG_INTER") {2743}2744RegInterface::~RegInterface() {2745}27462747void RegInterface::dump() {2748output(stderr);2749}27502751// Write info to output files2752void RegInterface::output(FILE *fp) {2753Interface::output(fp);2754}27552756//------------------------------ConstInterface---------------------------------2757ConstInterface::ConstInterface() : Interface("CONST_INTER") {2758}2759ConstInterface::~ConstInterface() {2760}27612762void ConstInterface::dump() {2763output(stderr);2764}27652766// Write info to output files2767void ConstInterface::output(FILE *fp) {2768Interface::output(fp);2769}27702771//------------------------------MemInterface-----------------------------------2772MemInterface::MemInterface(char *base, char *index, char *scale, char *disp)2773: Interface("MEMORY_INTER"), _base(base), _index(index), _scale(scale), _disp(disp) {2774}2775MemInterface::~MemInterface() {2776// not owner of any character arrays2777}27782779void MemInterface::dump() {2780output(stderr);2781}27822783// Write info to output files2784void MemInterface::output(FILE *fp) {2785Interface::output(fp);2786if ( _base != NULL ) fprintf(fp," base == %s\n", _base);2787if ( _index != NULL ) fprintf(fp," index == %s\n", _index);2788if ( _scale != NULL ) fprintf(fp," scale == %s\n", _scale);2789if ( _disp != NULL ) fprintf(fp," disp == %s\n", _disp);2790// fprintf(fp,"\n");2791}27922793//------------------------------CondInterface----------------------------------2794CondInterface::CondInterface(const char* equal, const char* equal_format,2795const char* not_equal, const char* not_equal_format,2796const char* less, const char* less_format,2797const char* greater_equal, const char* greater_equal_format,2798const char* less_equal, const char* less_equal_format,2799const char* greater, const char* greater_format,2800const char* overflow, const char* overflow_format,2801const char* no_overflow, const char* no_overflow_format)2802: Interface("COND_INTER"),2803_equal(equal), _equal_format(equal_format),2804_not_equal(not_equal), _not_equal_format(not_equal_format),2805_less(less), _less_format(less_format),2806_greater_equal(greater_equal), _greater_equal_format(greater_equal_format),2807_less_equal(less_equal), _less_equal_format(less_equal_format),2808_greater(greater), _greater_format(greater_format),2809_overflow(overflow), _overflow_format(overflow_format),2810_no_overflow(no_overflow), _no_overflow_format(no_overflow_format) {2811}2812CondInterface::~CondInterface() {2813// not owner of any character arrays2814}28152816void CondInterface::dump() {2817output(stderr);2818}28192820// Write info to output files2821void CondInterface::output(FILE *fp) {2822Interface::output(fp);2823if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal);2824if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal);2825if ( _less != NULL ) fprintf(fp," less == %s\n", _less);2826if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal);2827if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal);2828if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater);2829if ( _overflow != NULL ) fprintf(fp," overflow == %s\n", _overflow);2830if ( _no_overflow != NULL ) fprintf(fp," no_overflow == %s\n", _no_overflow);2831// fprintf(fp,"\n");2832}28332834//------------------------------ConstructRule----------------------------------2835ConstructRule::ConstructRule(char *cnstr)2836: _construct(cnstr) {2837}2838ConstructRule::~ConstructRule() {2839}28402841void ConstructRule::dump() {2842output(stderr);2843}28442845void ConstructRule::output(FILE *fp) {2846fprintf(fp,"\nConstruct Rule\n"); // Write to output files2847}284828492850//==============================Shared Forms===================================2851//------------------------------AttributeForm----------------------------------2852int AttributeForm::_insId = 0; // start counter at 02853int AttributeForm::_opId = 0; // start counter at 02854const char* AttributeForm::_ins_cost = "ins_cost"; // required name2855const char* AttributeForm::_op_cost = "op_cost"; // required name28562857AttributeForm::AttributeForm(char *attr, int type, char *attrdef)2858: Form(Form::ATTR), _attrname(attr), _atype(type), _attrdef(attrdef) {2859if (type==OP_ATTR) {2860id = ++_opId;2861}2862else if (type==INS_ATTR) {2863id = ++_insId;2864}2865else assert( false,"");2866}2867AttributeForm::~AttributeForm() {2868}28692870// Dynamic type check2871AttributeForm *AttributeForm::is_attribute() const {2872return (AttributeForm*)this;2873}287428752876// inlined // int AttributeForm::type() { return id;}28772878void AttributeForm::dump() {2879output(stderr);2880}28812882void AttributeForm::output(FILE *fp) {2883if( _attrname && _attrdef ) {2884fprintf(fp,"\n// AttributeForm \nstatic const int %s = %s;\n",2885_attrname, _attrdef);2886}2887else {2888fprintf(fp,"\n// AttributeForm missing name %s or definition %s\n",2889(_attrname?_attrname:""), (_attrdef?_attrdef:"") );2890}2891}28922893//------------------------------Component--------------------------------------2894Component::Component(const char *name, const char *type, int usedef)2895: _name(name), _type(type), _usedef(usedef) {2896_ftype = Form::COMP;2897}2898Component::~Component() {2899}29002901// True if this component is equal to the parameter.2902bool Component::is(int use_def_kill_enum) const {2903return (_usedef == use_def_kill_enum ? true : false);2904}2905// True if this component is used/def'd/kill'd as the parameter suggests.2906bool Component::isa(int use_def_kill_enum) const {2907return (_usedef & use_def_kill_enum) == use_def_kill_enum;2908}29092910// Extend this component with additional use/def/kill behavior2911int Component::promote_use_def_info(int new_use_def) {2912_usedef |= new_use_def;29132914return _usedef;2915}29162917// Check the base type of this component, if it has one2918const char *Component::base_type(FormDict &globals) {2919const Form *frm = globals[_type];2920if (frm == NULL) return NULL;2921OperandForm *op = frm->is_operand();2922if (op == NULL) return NULL;2923if (op->ideal_only()) return op->_ident;2924return (char *)op->ideal_type(globals);2925}29262927void Component::dump() {2928output(stderr);2929}29302931void Component::output(FILE *fp) {2932fprintf(fp,"Component:"); // Write to output files2933fprintf(fp, " name = %s", _name);2934fprintf(fp, ", type = %s", _type);2935assert(_usedef != 0, "unknown effect");2936fprintf(fp, ", use/def = %s\n", getUsedefName());2937}293829392940//------------------------------ComponentList---------------------------------2941ComponentList::ComponentList() : NameList(), _matchcnt(0) {2942}2943ComponentList::~ComponentList() {2944// // This list may not own its elements if copied via assignment2945// Component *component;2946// for (reset(); (component = iter()) != NULL;) {2947// delete component;2948// }2949}29502951void ComponentList::insert(Component *component, bool mflag) {2952NameList::addName((char *)component);2953if(mflag) _matchcnt++;2954}2955void ComponentList::insert(const char *name, const char *opType, int usedef,2956bool mflag) {2957Component * component = new Component(name, opType, usedef);2958insert(component, mflag);2959}2960Component *ComponentList::current() { return (Component*)NameList::current(); }2961Component *ComponentList::iter() { return (Component*)NameList::iter(); }2962Component *ComponentList::match_iter() {2963if(_iter < _matchcnt) return (Component*)NameList::iter();2964return NULL;2965}2966Component *ComponentList::post_match_iter() {2967Component *comp = iter();2968// At end of list?2969if ( comp == NULL ) {2970return comp;2971}2972// In post-match components?2973if (_iter > match_count()-1) {2974return comp;2975}29762977return post_match_iter();2978}29792980void ComponentList::reset() { NameList::reset(); }2981int ComponentList::count() { return NameList::count(); }29822983Component *ComponentList::operator[](int position) {2984// Shortcut complete iteration if there are not enough entries2985if (position >= count()) return NULL;29862987int index = 0;2988Component *component = NULL;2989for (reset(); (component = iter()) != NULL;) {2990if (index == position) {2991return component;2992}2993++index;2994}29952996return NULL;2997}29982999const Component *ComponentList::search(const char *name) {3000PreserveIter pi(this);3001reset();3002for( Component *comp = NULL; ((comp = iter()) != NULL); ) {3003if( strcmp(comp->_name,name) == 0 ) return comp;3004}30053006return NULL;3007}30083009// Return number of USEs + number of DEFs3010// When there are no components, or the first component is a USE,3011// then we add '1' to hold a space for the 'result' operand.3012int ComponentList::num_operands() {3013PreserveIter pi(this);3014uint count = 1; // result operand3015uint position = 0;30163017Component *component = NULL;3018for( reset(); (component = iter()) != NULL; ++position ) {3019if( component->isa(Component::USE) ||3020( position == 0 && (! component->isa(Component::DEF))) ) {3021++count;3022}3023}30243025return count;3026}30273028// Return zero-based position of operand 'name' in list; -1 if not in list.3029// if parameter 'usedef' is ::USE, it will match USE, USE_DEF, ...3030int ComponentList::operand_position(const char *name, int usedef, Form *fm) {3031PreserveIter pi(this);3032int position = 0;3033int num_opnds = num_operands();3034Component *component;3035Component* preceding_non_use = NULL;3036Component* first_def = NULL;3037for (reset(); (component = iter()) != NULL; ++position) {3038// When the first component is not a DEF,3039// leave space for the result operand!3040if ( position==0 && (! component->isa(Component::DEF)) ) {3041++position;3042++num_opnds;3043}3044if (strcmp(name, component->_name)==0 && (component->isa(usedef))) {3045// When the first entry in the component list is a DEF and a USE3046// Treat them as being separate, a DEF first, then a USE3047if( position==03048&& usedef==Component::USE && component->isa(Component::DEF) ) {3049assert(position+1 < num_opnds, "advertised index in bounds");3050return position+1;3051} else {3052if( preceding_non_use && strcmp(component->_name, preceding_non_use->_name) ) {3053fprintf(stderr, "the name '%s(%s)' should not precede the name '%s(%s)'",3054preceding_non_use->_name, preceding_non_use->getUsedefName(),3055name, component->getUsedefName());3056if (fm && fm->is_instruction()) fprintf(stderr, "in form '%s'", fm->is_instruction()->_ident);3057if (fm && fm->is_operand()) fprintf(stderr, "in form '%s'", fm->is_operand()->_ident);3058fprintf(stderr, "\n");3059}3060if( position >= num_opnds ) {3061fprintf(stderr, "the name '%s' is too late in its name list", name);3062if (fm && fm->is_instruction()) fprintf(stderr, "in form '%s'", fm->is_instruction()->_ident);3063if (fm && fm->is_operand()) fprintf(stderr, "in form '%s'", fm->is_operand()->_ident);3064fprintf(stderr, "\n");3065}3066assert(position < num_opnds, "advertised index in bounds");3067return position;3068}3069}3070if( component->isa(Component::DEF)3071&& component->isa(Component::USE) ) {3072++position;3073if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3074}3075if( component->isa(Component::DEF) && !first_def ) {3076first_def = component;3077}3078if( !component->isa(Component::USE) && component != first_def ) {3079preceding_non_use = component;3080} else if( preceding_non_use && !strcmp(component->_name, preceding_non_use->_name) ) {3081preceding_non_use = NULL;3082}3083}3084return Not_in_list;3085}30863087// Find position for this name, regardless of use/def information3088int ComponentList::operand_position(const char *name) {3089PreserveIter pi(this);3090int position = 0;3091Component *component;3092for (reset(); (component = iter()) != NULL; ++position) {3093// When the first component is not a DEF,3094// leave space for the result operand!3095if ( position==0 && (! component->isa(Component::DEF)) ) {3096++position;3097}3098if (strcmp(name, component->_name)==0) {3099return position;3100}3101if( component->isa(Component::DEF)3102&& component->isa(Component::USE) ) {3103++position;3104if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3105}3106}3107return Not_in_list;3108}31093110int ComponentList::operand_position_format(const char *name, Form *fm) {3111PreserveIter pi(this);3112int first_position = operand_position(name);3113int use_position = operand_position(name, Component::USE, fm);31143115return ((first_position < use_position) ? use_position : first_position);3116}31173118int ComponentList::label_position() {3119PreserveIter pi(this);3120int position = 0;3121reset();3122for( Component *comp; (comp = iter()) != NULL; ++position) {3123// When the first component is not a DEF,3124// leave space for the result operand!3125if ( position==0 && (! comp->isa(Component::DEF)) ) {3126++position;3127}3128if (strcmp(comp->_type, "label")==0) {3129return position;3130}3131if( comp->isa(Component::DEF)3132&& comp->isa(Component::USE) ) {3133++position;3134if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3135}3136}31373138return -1;3139}31403141int ComponentList::method_position() {3142PreserveIter pi(this);3143int position = 0;3144reset();3145for( Component *comp; (comp = iter()) != NULL; ++position) {3146// When the first component is not a DEF,3147// leave space for the result operand!3148if ( position==0 && (! comp->isa(Component::DEF)) ) {3149++position;3150}3151if (strcmp(comp->_type, "method")==0) {3152return position;3153}3154if( comp->isa(Component::DEF)3155&& comp->isa(Component::USE) ) {3156++position;3157if( position != 1 ) --position; // only use two slots for the 1st USE_DEF3158}3159}31603161return -1;3162}31633164void ComponentList::dump() { output(stderr); }31653166void ComponentList::output(FILE *fp) {3167PreserveIter pi(this);3168fprintf(fp, "\n");3169Component *component;3170for (reset(); (component = iter()) != NULL;) {3171component->output(fp);3172}3173fprintf(fp, "\n");3174}31753176//------------------------------MatchNode--------------------------------------3177MatchNode::MatchNode(ArchDesc &ad, const char *result, const char *mexpr,3178const char *opType, MatchNode *lChild, MatchNode *rChild)3179: _AD(ad), _result(result), _name(mexpr), _opType(opType),3180_lChild(lChild), _rChild(rChild), _internalop(0), _numleaves(0),3181_commutative_id(0) {3182_numleaves = (lChild ? lChild->_numleaves : 0)3183+ (rChild ? rChild->_numleaves : 0);3184}31853186MatchNode::MatchNode(ArchDesc &ad, MatchNode& mnode)3187: _AD(ad), _result(mnode._result), _name(mnode._name),3188_opType(mnode._opType), _lChild(mnode._lChild), _rChild(mnode._rChild),3189_internalop(0), _numleaves(mnode._numleaves),3190_commutative_id(mnode._commutative_id) {3191}31923193MatchNode::MatchNode(ArchDesc &ad, MatchNode& mnode, int clone)3194: _AD(ad), _result(mnode._result), _name(mnode._name),3195_opType(mnode._opType),3196_internalop(0), _numleaves(mnode._numleaves),3197_commutative_id(mnode._commutative_id) {3198if (mnode._lChild) {3199_lChild = new MatchNode(ad, *mnode._lChild, clone);3200} else {3201_lChild = NULL;3202}3203if (mnode._rChild) {3204_rChild = new MatchNode(ad, *mnode._rChild, clone);3205} else {3206_rChild = NULL;3207}3208}32093210MatchNode::~MatchNode() {3211// // This node may not own its children if copied via assignment3212// if( _lChild ) delete _lChild;3213// if( _rChild ) delete _rChild;3214}32153216bool MatchNode::find_type(const char *type, int &position) const {3217if ( (_lChild != NULL) && (_lChild->find_type(type, position)) ) return true;3218if ( (_rChild != NULL) && (_rChild->find_type(type, position)) ) return true;32193220if (strcmp(type,_opType)==0) {3221return true;3222} else {3223++position;3224}3225return false;3226}32273228// Recursive call collecting info on top-level operands, not transitive.3229// Implementation does not modify state of internal structures.3230void MatchNode::append_components(FormDict& locals, ComponentList& components,3231bool def_flag) const {3232int usedef = def_flag ? Component::DEF : Component::USE;3233FormDict &globals = _AD.globalNames();32343235assert (_name != NULL, "MatchNode::build_components encountered empty node\n");3236// Base case3237if (_lChild==NULL && _rChild==NULL) {3238// If _opType is not an operation, do not build a component for it #####3239const Form *f = globals[_opType];3240if( f != NULL ) {3241// Add non-ideals that are operands, operand-classes,3242if( ! f->ideal_only()3243&& (f->is_opclass() || f->is_operand()) ) {3244components.insert(_name, _opType, usedef, true);3245}3246}3247return;3248}3249// Promote results of "Set" to DEF3250bool tmpdef_flag = (!strcmp(_opType, "Set")) ? true : false;3251if (_lChild) _lChild->append_components(locals, components, tmpdef_flag);3252tmpdef_flag = false; // only applies to component immediately following 'Set'3253if (_rChild) _rChild->append_components(locals, components, tmpdef_flag);3254}32553256// Find the n'th base-operand in the match node,3257// recursively investigates match rules of user-defined operands.3258//3259// Implementation does not modify state of internal structures since they3260// can be shared.3261bool MatchNode::base_operand(uint &position, FormDict &globals,3262const char * &result, const char * &name,3263const char * &opType) const {3264assert (_name != NULL, "MatchNode::base_operand encountered empty node\n");3265// Base case3266if (_lChild==NULL && _rChild==NULL) {3267// Check for special case: "Universe", "label"3268if (strcmp(_opType,"Universe") == 0 || strcmp(_opType,"label")==0 ) {3269if (position == 0) {3270result = _result;3271name = _name;3272opType = _opType;3273return 1;3274} else {3275-- position;3276return 0;3277}3278}32793280const Form *form = globals[_opType];3281MatchNode *matchNode = NULL;3282// Check for user-defined type3283if (form) {3284// User operand or instruction?3285OperandForm *opForm = form->is_operand();3286InstructForm *inForm = form->is_instruction();3287if ( opForm ) {3288matchNode = (MatchNode*)opForm->_matrule;3289} else if ( inForm ) {3290matchNode = (MatchNode*)inForm->_matrule;3291}3292}3293// if this is user-defined, recurse on match rule3294// User-defined operand and instruction forms have a match-rule.3295if (matchNode) {3296return (matchNode->base_operand(position,globals,result,name,opType));3297} else {3298// Either not a form, or a system-defined form (no match rule).3299if (position==0) {3300result = _result;3301name = _name;3302opType = _opType;3303return 1;3304} else {3305--position;3306return 0;3307}3308}33093310} else {3311// Examine the left child and right child as well3312if (_lChild) {3313if (_lChild->base_operand(position, globals, result, name, opType))3314return 1;3315}33163317if (_rChild) {3318if (_rChild->base_operand(position, globals, result, name, opType))3319return 1;3320}3321}33223323return 0;3324}33253326// Recursive call on all operands' match rules in my match rule.3327uint MatchNode::num_consts(FormDict &globals) const {3328uint index = 0;3329uint num_consts = 0;3330const char *result;3331const char *name;3332const char *opType;33333334for (uint position = index;3335base_operand(position,globals,result,name,opType); position = index) {3336++index;3337if( ideal_to_const_type(opType) ) num_consts++;3338}33393340return num_consts;3341}33423343// Recursive call on all operands' match rules in my match rule.3344// Constants in match rule subtree with specified type3345uint MatchNode::num_consts(FormDict &globals, Form::DataType type) const {3346uint index = 0;3347uint num_consts = 0;3348const char *result;3349const char *name;3350const char *opType;33513352for (uint position = index;3353base_operand(position,globals,result,name,opType); position = index) {3354++index;3355if( ideal_to_const_type(opType) == type ) num_consts++;3356}33573358return num_consts;3359}33603361// Recursive call on all operands' match rules in my match rule.3362uint MatchNode::num_const_ptrs(FormDict &globals) const {3363return num_consts( globals, Form::idealP );3364}33653366bool MatchNode::sets_result() const {3367return ( (strcmp(_name,"Set") == 0) ? true : false );3368}33693370const char *MatchNode::reduce_right(FormDict &globals) const {3371// If there is no right reduction, return NULL.3372const char *rightStr = NULL;33733374// If we are a "Set", start from the right child.3375const MatchNode *const mnode = sets_result() ?3376(const MatchNode *)this->_rChild :3377(const MatchNode *)this;33783379// If our right child exists, it is the right reduction3380if ( mnode->_rChild ) {3381rightStr = mnode->_rChild->_internalop ? mnode->_rChild->_internalop3382: mnode->_rChild->_opType;3383}3384// Else, May be simple chain rule: (Set dst operand_form), rightStr=NULL;3385return rightStr;3386}33873388const char *MatchNode::reduce_left(FormDict &globals) const {3389// If there is no left reduction, return NULL.3390const char *leftStr = NULL;33913392// If we are a "Set", start from the right child.3393const MatchNode *const mnode = sets_result() ?3394(const MatchNode *)this->_rChild :3395(const MatchNode *)this;33963397// If our left child exists, it is the left reduction3398if ( mnode->_lChild ) {3399leftStr = mnode->_lChild->_internalop ? mnode->_lChild->_internalop3400: mnode->_lChild->_opType;3401} else {3402// May be simple chain rule: (Set dst operand_form_source)3403if ( sets_result() ) {3404OperandForm *oper = globals[mnode->_opType]->is_operand();3405if( oper ) {3406leftStr = mnode->_opType;3407}3408}3409}3410return leftStr;3411}34123413//------------------------------count_instr_names------------------------------3414// Count occurrences of operands names in the leaves of the instruction3415// match rule.3416void MatchNode::count_instr_names( Dict &names ) {3417if( _lChild ) _lChild->count_instr_names(names);3418if( _rChild ) _rChild->count_instr_names(names);3419if( !_lChild && !_rChild ) {3420uintptr_t cnt = (uintptr_t)names[_name];3421cnt++; // One more name found3422names.Insert(_name,(void*)cnt);3423}3424}34253426//------------------------------build_instr_pred-------------------------------3427// Build a path to 'name' in buf. Actually only build if cnt is zero, so we3428// can skip some leading instances of 'name'.3429int MatchNode::build_instr_pred( char *buf, const char *name, int cnt, int path_bitmask, int level) {3430if( _lChild ) {3431cnt = _lChild->build_instr_pred(buf, name, cnt, path_bitmask, level+1);3432if( cnt < 0 ) {3433return cnt; // Found it, all done3434}3435}3436if( _rChild ) {3437path_bitmask |= 1 << level;3438cnt = _rChild->build_instr_pred( buf, name, cnt, path_bitmask, level+1);3439if( cnt < 0 ) {3440return cnt; // Found it, all done3441}3442}3443if( !_lChild && !_rChild ) { // Found a leaf3444// Wrong name? Give up...3445if( strcmp(name,_name) ) return cnt;3446if( !cnt ) {3447for(int i = 0; i < level; i++) {3448int kid = path_bitmask & (1 << i);3449if (0 == kid) {3450strcpy( buf, "_kids[0]->" );3451} else {3452strcpy( buf, "_kids[1]->" );3453}3454buf += 10;3455}3456strcpy( buf, "_leaf" );3457}3458return cnt-1;3459}3460return cnt;3461}346234633464//------------------------------build_internalop-------------------------------3465// Build string representation of subtree3466void MatchNode::build_internalop( ) {3467char *iop, *subtree;3468const char *lstr, *rstr;3469// Build string representation of subtree3470// Operation lchildType rchildType3471int len = (int)strlen(_opType) + 4;3472lstr = (_lChild) ? ((_lChild->_internalop) ?3473_lChild->_internalop : _lChild->_opType) : "";3474rstr = (_rChild) ? ((_rChild->_internalop) ?3475_rChild->_internalop : _rChild->_opType) : "";3476len += (int)strlen(lstr) + (int)strlen(rstr);3477subtree = (char *)AdlAllocateHeap(len);3478sprintf(subtree,"_%s_%s_%s", _opType, lstr, rstr);3479// Hash the subtree string in _internalOps; if a name exists, use it3480iop = (char *)_AD._internalOps[subtree];3481// Else create a unique name, and add it to the hash table3482if (iop == NULL) {3483iop = subtree;3484_AD._internalOps.Insert(subtree, iop);3485_AD._internalOpNames.addName(iop);3486_AD._internalMatch.Insert(iop, this);3487}3488// Add the internal operand name to the MatchNode3489_internalop = iop;3490_result = iop;3491}349234933494void MatchNode::dump() {3495output(stderr);3496}34973498void MatchNode::output(FILE *fp) {3499if (_lChild==0 && _rChild==0) {3500fprintf(fp," %s",_name); // operand3501}3502else {3503fprintf(fp," (%s ",_name); // " (opcodeName "3504if(_lChild) _lChild->output(fp); // left operand3505if(_rChild) _rChild->output(fp); // right operand3506fprintf(fp,")"); // ")"3507}3508}35093510int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {3511static const char *needs_ideal_memory_list[] = {3512"StoreI","StoreL","StoreP","StoreN","StoreNKlass","StoreD","StoreF" ,3513"StoreB","StoreC","Store" ,"StoreFP",3514"LoadI", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,3515"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,3516"StoreVector", "LoadVector", "LoadVectorGather", "StoreVectorScatter", "LoadVectorMasked", "StoreVectorMasked",3517"LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",3518"LoadPLocked",3519"StorePConditional", "StoreIConditional", "StoreLConditional",3520"CompareAndSwapB", "CompareAndSwapS", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN",3521"WeakCompareAndSwapB", "WeakCompareAndSwapS", "WeakCompareAndSwapI", "WeakCompareAndSwapL", "WeakCompareAndSwapP", "WeakCompareAndSwapN",3522"CompareAndExchangeB", "CompareAndExchangeS", "CompareAndExchangeI", "CompareAndExchangeL", "CompareAndExchangeP", "CompareAndExchangeN",3523#if INCLUDE_SHENANDOAHGC3524"ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN",3525#endif3526"StoreCM",3527"GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP",3528"GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN",3529"ClearArray"3530};3531int cnt = sizeof(needs_ideal_memory_list)/sizeof(char*);3532if( strcmp(_opType,"PrefetchAllocation")==0 )3533return 1;3534if( strcmp(_opType,"CacheWB")==0 )3535return 1;3536if( strcmp(_opType,"CacheWBPreSync")==0 )3537return 1;3538if( strcmp(_opType,"CacheWBPostSync")==0 )3539return 1;3540if( _lChild ) {3541const char *opType = _lChild->_opType;3542for( int i=0; i<cnt; i++ )3543if( strcmp(opType,needs_ideal_memory_list[i]) == 0 )3544return 1;3545if( _lChild->needs_ideal_memory_edge(globals) )3546return 1;3547}3548if( _rChild ) {3549const char *opType = _rChild->_opType;3550for( int i=0; i<cnt; i++ )3551if( strcmp(opType,needs_ideal_memory_list[i]) == 0 )3552return 1;3553if( _rChild->needs_ideal_memory_edge(globals) )3554return 1;3555}35563557return 0;3558}35593560// TRUE if defines a derived oop, and so needs a base oop edge present3561// post-matching.3562int MatchNode::needs_base_oop_edge() const {3563if( !strcmp(_opType,"AddP") ) return 1;3564if( strcmp(_opType,"Set") ) return 0;3565return !strcmp(_rChild->_opType,"AddP");3566}35673568int InstructForm::needs_base_oop_edge(FormDict &globals) const {3569if( is_simple_chain_rule(globals) ) {3570const char *src = _matrule->_rChild->_opType;3571OperandForm *src_op = globals[src]->is_operand();3572assert( src_op, "Not operand class of chain rule" );3573return src_op->_matrule ? src_op->_matrule->needs_base_oop_edge() : 0;3574} // Else check instruction35753576return _matrule ? _matrule->needs_base_oop_edge() : 0;3577}357835793580//-------------------------cisc spilling methods-------------------------------3581// helper routines and methods for detecting cisc-spilling instructions3582//-------------------------cisc_spill_merge------------------------------------3583int MatchNode::cisc_spill_merge(int left_spillable, int right_spillable) {3584int cisc_spillable = Maybe_cisc_spillable;35853586// Combine results of left and right checks3587if( (left_spillable == Maybe_cisc_spillable) && (right_spillable == Maybe_cisc_spillable) ) {3588// neither side is spillable, nor prevents cisc spilling3589cisc_spillable = Maybe_cisc_spillable;3590}3591else if( (left_spillable == Maybe_cisc_spillable) && (right_spillable > Maybe_cisc_spillable) ) {3592// right side is spillable3593cisc_spillable = right_spillable;3594}3595else if( (right_spillable == Maybe_cisc_spillable) && (left_spillable > Maybe_cisc_spillable) ) {3596// left side is spillable3597cisc_spillable = left_spillable;3598}3599else if( (left_spillable == Not_cisc_spillable) || (right_spillable == Not_cisc_spillable) ) {3600// left or right prevents cisc spilling this instruction3601cisc_spillable = Not_cisc_spillable;3602}3603else {3604// Only allow one to spill3605cisc_spillable = Not_cisc_spillable;3606}36073608return cisc_spillable;3609}36103611//-------------------------root_ops_match--------------------------------------3612bool static root_ops_match(FormDict &globals, const char *op1, const char *op2) {3613// Base Case: check that the current operands/operations match3614assert( op1, "Must have op's name");3615assert( op2, "Must have op's name");3616const Form *form1 = globals[op1];3617const Form *form2 = globals[op2];36183619return (form1 == form2);3620}36213622//-------------------------cisc_spill_match_node-------------------------------3623// Recursively check two MatchRules for legal conversion via cisc-spilling3624int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* ®_type) {3625int cisc_spillable = Maybe_cisc_spillable;3626int left_spillable = Maybe_cisc_spillable;3627int right_spillable = Maybe_cisc_spillable;36283629// Check that each has same number of operands at this level3630if( (_lChild && !(mRule2->_lChild)) || (_rChild && !(mRule2->_rChild)) )3631return Not_cisc_spillable;36323633// Base Case: check that the current operands/operations match3634// or are CISC spillable3635assert( _opType, "Must have _opType");3636assert( mRule2->_opType, "Must have _opType");3637const Form *form = globals[_opType];3638const Form *form2 = globals[mRule2->_opType];3639if( form == form2 ) {3640cisc_spillable = Maybe_cisc_spillable;3641} else {3642const InstructForm *form2_inst = form2 ? form2->is_instruction() : NULL;3643const char *name_left = mRule2->_lChild ? mRule2->_lChild->_opType : NULL;3644const char *name_right = mRule2->_rChild ? mRule2->_rChild->_opType : NULL;3645DataType data_type = Form::none;3646if (form->is_operand()) {3647// Make sure the loadX matches the type of the reg3648data_type = form->ideal_to_Reg_type(form->is_operand()->ideal_type(globals));3649}3650// Detect reg vs (loadX memory)3651if( form->is_cisc_reg(globals)3652&& form2_inst3653&& data_type != Form::none3654&& (is_load_from_memory(mRule2->_opType) == data_type) // reg vs. (load memory)3655&& (name_left != NULL) // NOT (load)3656&& (name_right == NULL) ) { // NOT (load memory foo)3657const Form *form2_left = globals[name_left];3658if( form2_left && form2_left->is_cisc_mem(globals) ) {3659cisc_spillable = Is_cisc_spillable;3660operand = _name;3661reg_type = _result;3662return Is_cisc_spillable;3663} else {3664cisc_spillable = Not_cisc_spillable;3665}3666}3667// Detect reg vs memory3668else if (form->is_cisc_reg(globals) && form2 != NULL && form2->is_cisc_mem(globals)) {3669cisc_spillable = Is_cisc_spillable;3670operand = _name;3671reg_type = _result;3672return Is_cisc_spillable;3673} else {3674cisc_spillable = Not_cisc_spillable;3675}3676}36773678// If cisc is still possible, check rest of tree3679if( cisc_spillable == Maybe_cisc_spillable ) {3680// Check that each has same number of operands at this level3681if( (_lChild && !(mRule2->_lChild)) || (_rChild && !(mRule2->_rChild)) ) return Not_cisc_spillable;36823683// Check left operands3684if( (_lChild == NULL) && (mRule2->_lChild == NULL) ) {3685left_spillable = Maybe_cisc_spillable;3686} else if (_lChild != NULL) {3687left_spillable = _lChild->cisc_spill_match(globals, registers, mRule2->_lChild, operand, reg_type);3688}36893690// Check right operands3691if( (_rChild == NULL) && (mRule2->_rChild == NULL) ) {3692right_spillable = Maybe_cisc_spillable;3693} else if (_rChild != NULL) {3694right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type);3695}36963697// Combine results of left and right checks3698cisc_spillable = cisc_spill_merge(left_spillable, right_spillable);3699}37003701return cisc_spillable;3702}37033704//---------------------------cisc_spill_match_rule------------------------------3705// Recursively check two MatchRules for legal conversion via cisc-spilling3706// This method handles the root of Match tree,3707// general recursive checks done in MatchNode3708int MatchRule::matchrule_cisc_spill_match(FormDict& globals, RegisterForm* registers,3709MatchRule* mRule2, const char* &operand,3710const char* ®_type) {3711int cisc_spillable = Maybe_cisc_spillable;3712int left_spillable = Maybe_cisc_spillable;3713int right_spillable = Maybe_cisc_spillable;37143715// Check that each sets a result3716if( !(sets_result() && mRule2->sets_result()) ) return Not_cisc_spillable;3717// Check that each has same number of operands at this level3718if( (_lChild && !(mRule2->_lChild)) || (_rChild && !(mRule2->_rChild)) ) return Not_cisc_spillable;37193720// Check left operands: at root, must be target of 'Set'3721if( (_lChild == NULL) || (mRule2->_lChild == NULL) ) {3722left_spillable = Not_cisc_spillable;3723} else {3724// Do not support cisc-spilling instruction's target location3725if( root_ops_match(globals, _lChild->_opType, mRule2->_lChild->_opType) ) {3726left_spillable = Maybe_cisc_spillable;3727} else {3728left_spillable = Not_cisc_spillable;3729}3730}37313732// Check right operands: recursive walk to identify reg->mem operand3733if (_rChild == NULL) {3734if (mRule2->_rChild == NULL) {3735right_spillable = Maybe_cisc_spillable;3736} else {3737assert(0, "_rChild should not be NULL");3738}3739} else {3740right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type);3741}37423743// Combine results of left and right checks3744cisc_spillable = cisc_spill_merge(left_spillable, right_spillable);37453746return cisc_spillable;3747}37483749//----------------------------- equivalent ------------------------------------3750// Recursively check to see if two match rules are equivalent.3751// This rule handles the root.3752bool MatchRule::equivalent(FormDict &globals, MatchNode *mRule2) {3753// Check that each sets a result3754if (sets_result() != mRule2->sets_result()) {3755return false;3756}37573758// Check that the current operands/operations match3759assert( _opType, "Must have _opType");3760assert( mRule2->_opType, "Must have _opType");3761const Form *form = globals[_opType];3762const Form *form2 = globals[mRule2->_opType];3763if( form != form2 ) {3764return false;3765}37663767if (_lChild ) {3768if( !_lChild->equivalent(globals, mRule2->_lChild) )3769return false;3770} else if (mRule2->_lChild) {3771return false; // I have NULL left child, mRule2 has non-NULL left child.3772}37733774if (_rChild ) {3775if( !_rChild->equivalent(globals, mRule2->_rChild) )3776return false;3777} else if (mRule2->_rChild) {3778return false; // I have NULL right child, mRule2 has non-NULL right child.3779}37803781// We've made it through the gauntlet.3782return true;3783}37843785//----------------------------- equivalent ------------------------------------3786// Recursively check to see if two match rules are equivalent.3787// This rule handles the operands.3788bool MatchNode::equivalent(FormDict &globals, MatchNode *mNode2) {3789if( !mNode2 )3790return false;37913792// Check that the current operands/operations match3793assert( _opType, "Must have _opType");3794assert( mNode2->_opType, "Must have _opType");3795const Form *form = globals[_opType];3796const Form *form2 = globals[mNode2->_opType];3797if( form != form2 ) {3798return false;3799}38003801// Check that their children also match3802if (_lChild ) {3803if( !_lChild->equivalent(globals, mNode2->_lChild) )3804return false;3805} else if (mNode2->_lChild) {3806return false; // I have NULL left child, mNode2 has non-NULL left child.3807}38083809if (_rChild ) {3810if( !_rChild->equivalent(globals, mNode2->_rChild) )3811return false;3812} else if (mNode2->_rChild) {3813return false; // I have NULL right child, mNode2 has non-NULL right child.3814}38153816// We've made it through the gauntlet.3817return true;3818}38193820//-------------------------- has_commutative_op -------------------------------3821// Recursively check for commutative operations with subtree operands3822// which could be swapped.3823void MatchNode::count_commutative_op(int& count) {3824static const char *commut_op_list[] = {3825"AddI","AddL","AddF","AddD",3826"AddVB","AddVS","AddVI","AddVL","AddVF","AddVD",3827"AndI","AndL",3828"AndV",3829"MaxI","MinI","MaxF","MinF","MaxD","MinD",3830"MaxV", "MinV",3831"MulI","MulL","MulF","MulD",3832"MulVB","MulVS","MulVI","MulVL","MulVF","MulVD",3833"OrI","OrL",3834"OrV",3835"XorI","XorL",3836"XorV"3837};3838int cnt = sizeof(commut_op_list)/sizeof(char*);38393840if( _lChild && _rChild && (_lChild->_lChild || _rChild->_lChild) ) {3841// Don't swap if right operand is an immediate constant.3842bool is_const = false;3843if( _rChild->_lChild == NULL && _rChild->_rChild == NULL ) {3844FormDict &globals = _AD.globalNames();3845const Form *form = globals[_rChild->_opType];3846if ( form ) {3847OperandForm *oper = form->is_operand();3848if( oper && oper->interface_type(globals) == Form::constant_interface )3849is_const = true;3850}3851}3852if( !is_const ) {3853for( int i=0; i<cnt; i++ ) {3854if( strcmp(_opType, commut_op_list[i]) == 0 ) {3855count++;3856_commutative_id = count; // id should be > 03857break;3858}3859}3860}3861}3862if( _lChild )3863_lChild->count_commutative_op(count);3864if( _rChild )3865_rChild->count_commutative_op(count);3866}38673868//-------------------------- swap_commutative_op ------------------------------3869// Recursively swap specified commutative operation with subtree operands.3870void MatchNode::swap_commutative_op(bool atroot, int id) {3871if( _commutative_id == id ) { // id should be > 03872assert(_lChild && _rChild && (_lChild->_lChild || _rChild->_lChild ),3873"not swappable operation");3874MatchNode* tmp = _lChild;3875_lChild = _rChild;3876_rChild = tmp;3877// Don't exit here since we need to build internalop.3878}38793880bool is_set = ( strcmp(_opType, "Set") == 0 );3881if( _lChild )3882_lChild->swap_commutative_op(is_set, id);3883if( _rChild )3884_rChild->swap_commutative_op(is_set, id);38853886// If not the root, reduce this subtree to an internal operand3887if( !atroot && (_lChild || _rChild) ) {3888build_internalop();3889}3890}38913892//-------------------------- swap_commutative_op ------------------------------3893// Recursively swap specified commutative operation with subtree operands.3894void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) {3895assert(match_rules_cnt < 100," too many match rule clones");3896// Clone3897MatchRule* clone = new MatchRule(_AD, this);3898// Swap operands of commutative operation3899((MatchNode*)clone)->swap_commutative_op(true, count);3900char* buf = (char*) AdlAllocateHeap(strlen(instr_ident) + 4);3901sprintf(buf, "%s_%d", instr_ident, match_rules_cnt++);3902clone->_result = buf;39033904clone->_next = this->_next;3905this-> _next = clone;3906if( (--count) > 0 ) {3907this-> matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);3908clone->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);3909}3910}39113912//------------------------------MatchRule--------------------------------------3913MatchRule::MatchRule(ArchDesc &ad)3914: MatchNode(ad), _depth(0), _construct(NULL), _numchilds(0) {3915_next = NULL;3916}39173918MatchRule::MatchRule(ArchDesc &ad, MatchRule* mRule)3919: MatchNode(ad, *mRule, 0), _depth(mRule->_depth),3920_construct(mRule->_construct), _numchilds(mRule->_numchilds) {3921_next = NULL;3922}39233924MatchRule::MatchRule(ArchDesc &ad, MatchNode* mroot, int depth, char *cnstr,3925int numleaves)3926: MatchNode(ad,*mroot), _depth(depth), _construct(cnstr),3927_numchilds(0) {3928_next = NULL;3929mroot->_lChild = NULL;3930mroot->_rChild = NULL;3931delete mroot;3932_numleaves = numleaves;3933_numchilds = (_lChild ? 1 : 0) + (_rChild ? 1 : 0);3934}3935MatchRule::~MatchRule() {3936}39373938// Recursive call collecting info on top-level operands, not transitive.3939// Implementation does not modify state of internal structures.3940void MatchRule::append_components(FormDict& locals, ComponentList& components, bool def_flag) const {3941assert (_name != NULL, "MatchNode::build_components encountered empty node\n");39423943MatchNode::append_components(locals, components,3944false /* not necessarily a def */);3945}39463947// Recursive call on all operands' match rules in my match rule.3948// Implementation does not modify state of internal structures since they3949// can be shared.3950// The MatchNode that is called first treats its3951bool MatchRule::base_operand(uint &position0, FormDict &globals,3952const char *&result, const char * &name,3953const char * &opType)const{3954uint position = position0;39553956return (MatchNode::base_operand( position, globals, result, name, opType));3957}395839593960bool MatchRule::is_base_register(FormDict &globals) const {3961uint position = 1;3962const char *result = NULL;3963const char *name = NULL;3964const char *opType = NULL;3965if (!base_operand(position, globals, result, name, opType)) {3966position = 0;3967if( base_operand(position, globals, result, name, opType) &&3968(strcmp(opType,"RegI")==0 ||3969strcmp(opType,"RegP")==0 ||3970strcmp(opType,"RegN")==0 ||3971strcmp(opType,"RegL")==0 ||3972strcmp(opType,"RegF")==0 ||3973strcmp(opType,"RegD")==0 ||3974strcmp(opType,"RegVectMask")==0 ||3975strcmp(opType,"VecA")==0 ||3976strcmp(opType,"VecS")==0 ||3977strcmp(opType,"VecD")==0 ||3978strcmp(opType,"VecX")==0 ||3979strcmp(opType,"VecY")==0 ||3980strcmp(opType,"VecZ")==0 ||3981strcmp(opType,"Reg" )==0) ) {3982return 1;3983}3984}3985return 0;3986}39873988Form::DataType MatchRule::is_base_constant(FormDict &globals) const {3989uint position = 1;3990const char *result = NULL;3991const char *name = NULL;3992const char *opType = NULL;3993if (!base_operand(position, globals, result, name, opType)) {3994position = 0;3995if (base_operand(position, globals, result, name, opType)) {3996return ideal_to_const_type(opType);3997}3998}3999return Form::none;4000}40014002bool MatchRule::is_chain_rule(FormDict &globals) const {40034004// Check for chain rule, and do not generate a match list for it4005if ((_lChild == NULL) && (_rChild == NULL) ) {4006const Form *form = globals[_opType];4007// If this is ideal, then it is a base match, not a chain rule.4008if ( form && form->is_operand() && (!form->ideal_only())) {4009return true;4010}4011}4012// Check for "Set" form of chain rule, and do not generate a match list4013if (_rChild) {4014const char *rch = _rChild->_opType;4015const Form *form = globals[rch];4016if ((!strcmp(_opType,"Set") &&4017((form) && form->is_operand()))) {4018return true;4019}4020}4021return false;4022}40234024int MatchRule::is_ideal_copy() const {4025if (is_chain_rule(_AD.globalNames()) &&4026_lChild && strncmp(_lChild->_opType, "stackSlot", 9) == 0) {4027return 1;4028}4029return 0;4030}40314032int MatchRule::is_expensive() const {4033if( _rChild ) {4034const char *opType = _rChild->_opType;4035if( strcmp(opType,"AtanD")==0 ||4036strcmp(opType,"DivD")==0 ||4037strcmp(opType,"DivF")==0 ||4038strcmp(opType,"DivI")==0 ||4039strcmp(opType,"Log10D")==0 ||4040strcmp(opType,"ModD")==0 ||4041strcmp(opType,"ModF")==0 ||4042strcmp(opType,"ModI")==0 ||4043strcmp(opType,"SqrtD")==0 ||4044strcmp(opType,"SqrtF")==0 ||4045strcmp(opType,"TanD")==0 ||4046strcmp(opType,"ConvD2F")==0 ||4047strcmp(opType,"ConvD2I")==0 ||4048strcmp(opType,"ConvD2L")==0 ||4049strcmp(opType,"ConvF2D")==0 ||4050strcmp(opType,"ConvF2I")==0 ||4051strcmp(opType,"ConvF2L")==0 ||4052strcmp(opType,"ConvI2D")==0 ||4053strcmp(opType,"ConvI2F")==0 ||4054strcmp(opType,"ConvI2L")==0 ||4055strcmp(opType,"ConvL2D")==0 ||4056strcmp(opType,"ConvL2F")==0 ||4057strcmp(opType,"ConvL2I")==0 ||4058strcmp(opType,"DecodeN")==0 ||4059strcmp(opType,"EncodeP")==0 ||4060strcmp(opType,"EncodePKlass")==0 ||4061strcmp(opType,"DecodeNKlass")==0 ||4062strcmp(opType,"FmaD") == 0 ||4063strcmp(opType,"FmaF") == 0 ||4064strcmp(opType,"RoundDouble")==0 ||4065strcmp(opType,"RoundDoubleMode")==0 ||4066strcmp(opType,"RoundFloat")==0 ||4067strcmp(opType,"ReverseBytesI")==0 ||4068strcmp(opType,"ReverseBytesL")==0 ||4069strcmp(opType,"ReverseBytesUS")==0 ||4070strcmp(opType,"ReverseBytesS")==0 ||4071strcmp(opType,"ReplicateB")==0 ||4072strcmp(opType,"ReplicateS")==0 ||4073strcmp(opType,"ReplicateI")==0 ||4074strcmp(opType,"ReplicateL")==0 ||4075strcmp(opType,"ReplicateF")==0 ||4076strcmp(opType,"ReplicateD")==0 ||4077strcmp(opType,"AddReductionVI")==0 ||4078strcmp(opType,"AddReductionVL")==0 ||4079strcmp(opType,"AddReductionVF")==0 ||4080strcmp(opType,"AddReductionVD")==0 ||4081strcmp(opType,"MulReductionVI")==0 ||4082strcmp(opType,"MulReductionVL")==0 ||4083strcmp(opType,"MulReductionVF")==0 ||4084strcmp(opType,"MulReductionVD")==0 ||4085strcmp(opType,"MinReductionV")==0 ||4086strcmp(opType,"MaxReductionV")==0 ||4087strcmp(opType,"AndReductionV")==0 ||4088strcmp(opType,"OrReductionV")==0 ||4089strcmp(opType,"XorReductionV")==0 ||40900 /* 0 to line up columns nicely */ )4091return 1;4092}4093return 0;4094}40954096bool MatchRule::is_ideal_if() const {4097if( !_opType ) return false;4098return4099!strcmp(_opType,"If" ) ||4100!strcmp(_opType,"CountedLoopEnd");4101}41024103bool MatchRule::is_ideal_fastlock() const {4104if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4105return (strcmp(_rChild->_opType,"FastLock") == 0);4106}4107return false;4108}41094110bool MatchRule::is_ideal_membar() const {4111if( !_opType ) return false;4112return4113!strcmp(_opType,"MemBarAcquire") ||4114!strcmp(_opType,"MemBarRelease") ||4115!strcmp(_opType,"MemBarAcquireLock") ||4116!strcmp(_opType,"MemBarReleaseLock") ||4117!strcmp(_opType,"LoadFence" ) ||4118!strcmp(_opType,"StoreFence") ||4119!strcmp(_opType,"MemBarVolatile") ||4120!strcmp(_opType,"MemBarCPUOrder") ||4121!strcmp(_opType,"MemBarStoreStore") ||4122!strcmp(_opType,"OnSpinWait");4123}41244125bool MatchRule::is_ideal_loadPC() const {4126if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4127return (strcmp(_rChild->_opType,"LoadPC") == 0);4128}4129return false;4130}41314132bool MatchRule::is_ideal_box() const {4133if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4134return (strcmp(_rChild->_opType,"Box") == 0);4135}4136return false;4137}41384139bool MatchRule::is_ideal_goto() const {4140bool ideal_goto = false;41414142if( _opType && (strcmp(_opType,"Goto") == 0) ) {4143ideal_goto = true;4144}4145return ideal_goto;4146}41474148bool MatchRule::is_ideal_jump() const {4149if( _opType ) {4150if( !strcmp(_opType,"Jump") )4151return true;4152}4153return false;4154}41554156bool MatchRule::is_ideal_bool() const {4157if( _opType ) {4158if( !strcmp(_opType,"Bool") )4159return true;4160}4161return false;4162}416341644165Form::DataType MatchRule::is_ideal_load() const {4166Form::DataType ideal_load = Form::none;41674168if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4169const char *opType = _rChild->_opType;4170ideal_load = is_load_from_memory(opType);4171}41724173return ideal_load;4174}41754176bool MatchRule::is_vector() const {4177static const char *vector_list[] = {4178"AddVB","AddVS","AddVI","AddVL","AddVF","AddVD",4179"SubVB","SubVS","SubVI","SubVL","SubVF","SubVD",4180"MulVB","MulVS","MulVI","MulVL","MulVF","MulVD",4181"CMoveVD", "CMoveVF",4182"DivVF","DivVD",4183"AbsVB","AbsVS","AbsVI","AbsVL","AbsVF","AbsVD",4184"NegVF","NegVD","NegVI",4185"SqrtVD","SqrtVF",4186"AndV" ,"XorV" ,"OrV",4187"MaxV", "MinV",4188"AddReductionVI", "AddReductionVL",4189"AddReductionVF", "AddReductionVD",4190"MulReductionVI", "MulReductionVL",4191"MulReductionVF", "MulReductionVD",4192"MaxReductionV", "MinReductionV",4193"AndReductionV", "OrReductionV", "XorReductionV",4194"MulAddVS2VI", "MacroLogicV",4195"LShiftCntV","RShiftCntV",4196"LShiftVB","LShiftVS","LShiftVI","LShiftVL",4197"RShiftVB","RShiftVS","RShiftVI","RShiftVL",4198"URShiftVB","URShiftVS","URShiftVI","URShiftVL",4199"ReplicateB","ReplicateS","ReplicateI","ReplicateL","ReplicateF","ReplicateD",4200"RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector",4201"LoadVectorGather", "StoreVectorScatter",4202"VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",4203"VectorRearrange","VectorLoadShuffle", "VectorLoadConst",4204"VectorCastB2X", "VectorCastS2X", "VectorCastI2X",4205"VectorCastL2X", "VectorCastF2X", "VectorCastD2X",4206"VectorMaskWrapper", "VectorMaskCmp", "VectorReinterpret","LoadVectorMasked","StoreVectorMasked",4207"FmaVD", "FmaVF","PopCountVI",4208// Next are not supported currently.4209"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",4210"ExtractB","ExtractUB","ExtractC","ExtractS","ExtractI","ExtractL","ExtractF","ExtractD",4211"VectorMaskCast"4212};4213int cnt = sizeof(vector_list)/sizeof(char*);4214if (_rChild) {4215const char *opType = _rChild->_opType;4216for (int i=0; i<cnt; i++)4217if (strcmp(opType,vector_list[i]) == 0)4218return true;4219}4220return false;4221}422242234224bool MatchRule::skip_antidep_check() const {4225// Some loads operate on what is effectively immutable memory so we4226// should skip the anti dep computations. For some of these nodes4227// the rewritable field keeps the anti dep logic from triggering but4228// for certain kinds of LoadKlass it does not since they are4229// actually reading memory which could be rewritten by the runtime,4230// though never by generated code. This disables it uniformly for4231// the nodes that behave like this: LoadKlass, LoadNKlass and4232// LoadRange.4233if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4234const char *opType = _rChild->_opType;4235if (strcmp("LoadKlass", opType) == 0 ||4236strcmp("LoadNKlass", opType) == 0 ||4237strcmp("LoadRange", opType) == 0) {4238return true;4239}4240}42414242return false;4243}424442454246Form::DataType MatchRule::is_ideal_store() const {4247Form::DataType ideal_store = Form::none;42484249if ( _opType && (strcmp(_opType,"Set") == 0) && _rChild ) {4250const char *opType = _rChild->_opType;4251ideal_store = is_store_to_memory(opType);4252}42534254return ideal_store;4255}425642574258void MatchRule::dump() {4259output(stderr);4260}42614262// Write just one line.4263void MatchRule::output_short(FILE *fp) {4264fprintf(fp,"MatchRule: ( %s",_name);4265if (_lChild) _lChild->output(fp);4266if (_rChild) _rChild->output(fp);4267fprintf(fp," )");4268}42694270void MatchRule::output(FILE *fp) {4271output_short(fp);4272fprintf(fp,"\n nesting depth = %d\n", _depth);4273if (_result) fprintf(fp," Result Type = %s", _result);4274fprintf(fp,"\n");4275}42764277//------------------------------Attribute--------------------------------------4278Attribute::Attribute(char *id, char* val, int type)4279: _ident(id), _val(val), _atype(type) {4280}4281Attribute::~Attribute() {4282}42834284int Attribute::int_val(ArchDesc &ad) {4285// Make sure it is an integer constant:4286int result = 0;4287if (!_val || !ADLParser::is_int_token(_val, result)) {4288ad.syntax_err(0, "Attribute %s must have an integer value: %s",4289_ident, _val ? _val : "");4290}4291return result;4292}42934294void Attribute::dump() {4295output(stderr);4296} // Debug printer42974298// Write to output files4299void Attribute::output(FILE *fp) {4300fprintf(fp,"Attribute: %s %s\n", (_ident?_ident:""), (_val?_val:""));4301}43024303//------------------------------FormatRule----------------------------------4304FormatRule::FormatRule(char *temp)4305: _temp(temp) {4306}4307FormatRule::~FormatRule() {4308}43094310void FormatRule::dump() {4311output(stderr);4312}43134314// Write to output files4315void FormatRule::output(FILE *fp) {4316fprintf(fp,"\nFormat Rule: \n%s", (_temp?_temp:""));4317fprintf(fp,"\n");4318}431943204321