Path: blob/master/src/hotspot/share/adlc/output_c.cpp
41144 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// output_c.cpp - Class CPP file output routines for architecture definition2526#include "adlc.hpp"2728// Utilities to characterize effect statements29static bool is_def(int usedef) {30switch(usedef) {31case Component::DEF:32case Component::USE_DEF: return true; break;33}34return false;35}3637// Define an array containing the machine register names, strings.38static void defineRegNames(FILE *fp, RegisterForm *registers) {39if (registers) {40fprintf(fp,"\n");41fprintf(fp,"// An array of character pointers to machine register names.\n");42fprintf(fp,"const char *Matcher::regName[REG_COUNT] = {\n");4344// Output the register name for each register in the allocation classes45RegDef *reg_def = NULL;46RegDef *next = NULL;47registers->reset_RegDefs();48for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) {49next = registers->iter_RegDefs();50const char *comma = (next != NULL) ? "," : " // no trailing comma";51fprintf(fp," \"%s\"%s\n", reg_def->_regname, comma);52}5354// Finish defining enumeration55fprintf(fp,"};\n");5657fprintf(fp,"\n");58fprintf(fp,"// An array of character pointers to machine register names.\n");59fprintf(fp,"const VMReg OptoReg::opto2vm[REG_COUNT] = {\n");60reg_def = NULL;61next = NULL;62registers->reset_RegDefs();63for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) {64next = registers->iter_RegDefs();65const char *comma = (next != NULL) ? "," : " // no trailing comma";66fprintf(fp,"\t%s%s\n", reg_def->_concrete, comma);67}68// Finish defining array69fprintf(fp,"\t};\n");70fprintf(fp,"\n");7172fprintf(fp," OptoReg::Name OptoReg::vm2opto[ConcreteRegisterImpl::number_of_registers];\n");7374}75}7677// Define an array containing the machine register encoding values78static void defineRegEncodes(FILE *fp, RegisterForm *registers) {79if (registers) {80fprintf(fp,"\n");81fprintf(fp,"// An array of the machine register encode values\n");82fprintf(fp,"const unsigned char Matcher::_regEncode[REG_COUNT] = {\n");8384// Output the register encoding for each register in the allocation classes85RegDef *reg_def = NULL;86RegDef *next = NULL;87registers->reset_RegDefs();88for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) {89next = registers->iter_RegDefs();90const char* register_encode = reg_def->register_encode();91const char *comma = (next != NULL) ? "," : " // no trailing comma";92int encval;93if (!ADLParser::is_int_token(register_encode, encval)) {94fprintf(fp," %s%s // %s\n", register_encode, comma, reg_def->_regname);95} else {96// Output known constants in hex char format (backward compatibility).97assert(encval < 256, "Exceeded supported width for register encoding");98fprintf(fp," (unsigned char)'\\x%X'%s // %s\n", encval, comma, reg_def->_regname);99}100}101// Finish defining enumeration102fprintf(fp,"};\n");103104} // Done defining array105}106107// Output an enumeration of register class names108static void defineRegClassEnum(FILE *fp, RegisterForm *registers) {109if (registers) {110// Output an enumeration of register class names111fprintf(fp,"\n");112fprintf(fp,"// Enumeration of register class names\n");113fprintf(fp, "enum machRegisterClass {\n");114registers->_rclasses.reset();115for (const char *class_name = NULL; (class_name = registers->_rclasses.iter()) != NULL;) {116const char * class_name_to_upper = toUpper(class_name);117fprintf(fp," %s,\n", class_name_to_upper);118delete[] class_name_to_upper;119}120// Finish defining enumeration121fprintf(fp, " _last_Mach_Reg_Class\n");122fprintf(fp, "};\n");123}124}125126// Declare an enumeration of user-defined register classes127// and a list of register masks, one for each class.128void ArchDesc::declare_register_masks(FILE *fp_hpp) {129const char *rc_name;130131if (_register) {132// Build enumeration of user-defined register classes.133defineRegClassEnum(fp_hpp, _register);134135// Generate a list of register masks, one for each class.136fprintf(fp_hpp,"\n");137fprintf(fp_hpp,"// Register masks, one for each register class.\n");138_register->_rclasses.reset();139for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) {140RegClass *reg_class = _register->getRegClass(rc_name);141assert(reg_class, "Using an undefined register class");142reg_class->declare_register_masks(fp_hpp);143}144}145}146147// Generate an enumeration of user-defined register classes148// and a list of register masks, one for each class.149void ArchDesc::build_register_masks(FILE *fp_cpp) {150const char *rc_name;151152if (_register) {153// Generate a list of register masks, one for each class.154fprintf(fp_cpp,"\n");155fprintf(fp_cpp,"// Register masks, one for each register class.\n");156_register->_rclasses.reset();157for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) {158RegClass *reg_class = _register->getRegClass(rc_name);159assert(reg_class, "Using an undefined register class");160reg_class->build_register_masks(fp_cpp);161}162}163}164165// Compute an index for an array in the pipeline_reads_NNN arrays166static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, PipeClassForm *pipeclass)167{168int templen = 1;169int paramcount = 0;170const char *paramname;171172if (pipeclass->_parameters.count() == 0)173return -1;174175pipeclass->_parameters.reset();176paramname = pipeclass->_parameters.iter();177const PipeClassOperandForm *pipeopnd =178(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];179if (pipeopnd && !pipeopnd->isWrite() && strcmp(pipeopnd->_stage, "Universal"))180pipeclass->_parameters.reset();181182while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {183const PipeClassOperandForm *tmppipeopnd =184(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];185186if (tmppipeopnd)187templen += 10 + (int)strlen(tmppipeopnd->_stage);188else189templen += 19;190191paramcount++;192}193194// See if the count is zero195if (paramcount == 0) {196return -1;197}198199char *operand_stages = new char [templen];200operand_stages[0] = 0;201int i = 0;202templen = 0;203204pipeclass->_parameters.reset();205paramname = pipeclass->_parameters.iter();206pipeopnd = (const PipeClassOperandForm *)pipeclass->_localUsage[paramname];207if (pipeopnd && !pipeopnd->isWrite() && strcmp(pipeopnd->_stage, "Universal"))208pipeclass->_parameters.reset();209210while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {211const PipeClassOperandForm *tmppipeopnd =212(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];213templen += sprintf(&operand_stages[templen], " stage_%s%c\n",214tmppipeopnd ? tmppipeopnd->_stage : "undefined",215(++i < paramcount ? ',' : ' ') );216}217218// See if the same string is in the table219int ndx = pipeline_reads.index(operand_stages);220221// No, add it to the table222if (ndx < 0) {223pipeline_reads.addName(operand_stages);224ndx = pipeline_reads.index(operand_stages);225226fprintf(fp_cpp, "static const enum machPipelineStages pipeline_reads_%03d[%d] = {\n%s};\n\n",227ndx+1, paramcount, operand_stages);228}229else230delete [] operand_stages;231232return (ndx);233}234235// Compute an index for an array in the pipeline_res_stages_NNN arrays236static int pipeline_res_stages_initializer(237FILE *fp_cpp,238PipelineForm *pipeline,239NameList &pipeline_res_stages,240PipeClassForm *pipeclass)241{242const PipeClassResourceForm *piperesource;243int * res_stages = new int [pipeline->_rescount];244int i;245246for (i = 0; i < pipeline->_rescount; i++)247res_stages[i] = 0;248249for (pipeclass->_resUsage.reset();250(piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {251int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask();252for (i = 0; i < pipeline->_rescount; i++)253if ((1 << i) & used_mask) {254int stage = pipeline->_stages.index(piperesource->_stage);255if (res_stages[i] < stage+1)256res_stages[i] = stage+1;257}258}259260// Compute the length needed for the resource list261int commentlen = 0;262int max_stage = 0;263for (i = 0; i < pipeline->_rescount; i++) {264if (res_stages[i] == 0) {265if (max_stage < 9)266max_stage = 9;267}268else {269int stagelen = (int)strlen(pipeline->_stages.name(res_stages[i]-1));270if (max_stage < stagelen)271max_stage = stagelen;272}273274commentlen += (int)strlen(pipeline->_reslist.name(i));275}276277int templen = 1 + commentlen + pipeline->_rescount * (max_stage + 14);278279// Allocate space for the resource list280char * resource_stages = new char [templen];281282templen = 0;283for (i = 0; i < pipeline->_rescount; i++) {284const char * const resname =285res_stages[i] == 0 ? "undefined" : pipeline->_stages.name(res_stages[i]-1);286287templen += sprintf(&resource_stages[templen], " stage_%s%-*s // %s\n",288resname, max_stage - (int)strlen(resname) + 1,289(i < pipeline->_rescount-1) ? "," : "",290pipeline->_reslist.name(i));291}292293// See if the same string is in the table294int ndx = pipeline_res_stages.index(resource_stages);295296// No, add it to the table297if (ndx < 0) {298pipeline_res_stages.addName(resource_stages);299ndx = pipeline_res_stages.index(resource_stages);300301fprintf(fp_cpp, "static const enum machPipelineStages pipeline_res_stages_%03d[%d] = {\n%s};\n\n",302ndx+1, pipeline->_rescount, resource_stages);303}304else305delete [] resource_stages;306307delete [] res_stages;308309return (ndx);310}311312// Compute an index for an array in the pipeline_res_cycles_NNN arrays313static int pipeline_res_cycles_initializer(314FILE *fp_cpp,315PipelineForm *pipeline,316NameList &pipeline_res_cycles,317PipeClassForm *pipeclass)318{319const PipeClassResourceForm *piperesource;320int * res_cycles = new int [pipeline->_rescount];321int i;322323for (i = 0; i < pipeline->_rescount; i++)324res_cycles[i] = 0;325326for (pipeclass->_resUsage.reset();327(piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {328int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask();329for (i = 0; i < pipeline->_rescount; i++)330if ((1 << i) & used_mask) {331int cycles = piperesource->_cycles;332if (res_cycles[i] < cycles)333res_cycles[i] = cycles;334}335}336337// Pre-compute the string length338int templen;339int cyclelen = 0, commentlen = 0;340int max_cycles = 0;341char temp[32];342343for (i = 0; i < pipeline->_rescount; i++) {344if (max_cycles < res_cycles[i])345max_cycles = res_cycles[i];346templen = sprintf(temp, "%d", res_cycles[i]);347if (cyclelen < templen)348cyclelen = templen;349commentlen += (int)strlen(pipeline->_reslist.name(i));350}351352templen = 1 + commentlen + (cyclelen + 8) * pipeline->_rescount;353354// Allocate space for the resource list355char * resource_cycles = new char [templen];356357templen = 0;358359for (i = 0; i < pipeline->_rescount; i++) {360templen += sprintf(&resource_cycles[templen], " %*d%c // %s\n",361cyclelen, res_cycles[i], (i < pipeline->_rescount-1) ? ',' : ' ', pipeline->_reslist.name(i));362}363364// See if the same string is in the table365int ndx = pipeline_res_cycles.index(resource_cycles);366367// No, add it to the table368if (ndx < 0) {369pipeline_res_cycles.addName(resource_cycles);370ndx = pipeline_res_cycles.index(resource_cycles);371372fprintf(fp_cpp, "static const uint pipeline_res_cycles_%03d[%d] = {\n%s};\n\n",373ndx+1, pipeline->_rescount, resource_cycles);374}375else376delete [] resource_cycles;377378delete [] res_cycles;379380return (ndx);381}382383//typedef unsigned long long uint64_t;384385// Compute an index for an array in the pipeline_res_mask_NNN arrays386static int pipeline_res_mask_initializer(387FILE *fp_cpp,388PipelineForm *pipeline,389NameList &pipeline_res_mask,390NameList &pipeline_res_args,391PipeClassForm *pipeclass)392{393const PipeClassResourceForm *piperesource;394const uint rescount = pipeline->_rescount;395const uint maxcycleused = pipeline->_maxcycleused;396const uint cyclemasksize = (maxcycleused + 31) >> 5;397398int i, j;399int element_count = 0;400uint *res_mask = new uint [cyclemasksize];401uint resources_used = 0;402uint resources_used_exclusively = 0;403404for (pipeclass->_resUsage.reset();405(piperesource = (const PipeClassResourceForm*)pipeclass->_resUsage.iter()) != NULL; ) {406element_count++;407}408409// Pre-compute the string length410int templen;411int commentlen = 0;412int max_cycles = 0;413414int cyclelen = ((maxcycleused + 3) >> 2);415int masklen = (rescount + 3) >> 2;416417int cycledigit = 0;418for (i = maxcycleused; i > 0; i /= 10)419cycledigit++;420421int maskdigit = 0;422for (i = rescount; i > 0; i /= 10)423maskdigit++;424425static const char* pipeline_use_cycle_mask = "Pipeline_Use_Cycle_Mask";426static const char* pipeline_use_element = "Pipeline_Use_Element";427428templen = 1 +429(int)(strlen(pipeline_use_cycle_mask) + (int)strlen(pipeline_use_element) +430(cyclemasksize * 12) + masklen + (cycledigit * 2) + 30) * element_count;431432// Allocate space for the resource list433char * resource_mask = new char [templen];434char * last_comma = NULL;435436templen = 0;437438for (pipeclass->_resUsage.reset();439(piperesource = (const PipeClassResourceForm*)pipeclass->_resUsage.iter()) != NULL; ) {440int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask();441442if (!used_mask) {443fprintf(stderr, "*** used_mask is 0 ***\n");444}445446resources_used |= used_mask;447448uint lb, ub;449450for (lb = 0; (used_mask & (1 << lb)) == 0; lb++);451for (ub = 31; (used_mask & (1 << ub)) == 0; ub--);452453if (lb == ub) {454resources_used_exclusively |= used_mask;455}456457int formatlen =458sprintf(&resource_mask[templen], " %s(0x%0*x, %*d, %*d, %s %s(",459pipeline_use_element,460masklen, used_mask,461cycledigit, lb, cycledigit, ub,462((used_mask & (used_mask-1)) != 0) ? "true, " : "false,",463pipeline_use_cycle_mask);464465templen += formatlen;466467memset(res_mask, 0, cyclemasksize * sizeof(uint));468469int cycles = piperesource->_cycles;470uint stage = pipeline->_stages.index(piperesource->_stage);471if ((uint)NameList::Not_in_list == stage) {472fprintf(stderr,473"pipeline_res_mask_initializer: "474"semantic error: "475"pipeline stage undeclared: %s\n",476piperesource->_stage);477exit(1);478}479uint upper_limit = stage + cycles - 1;480uint lower_limit = stage - 1;481uint upper_idx = upper_limit >> 5;482uint lower_idx = lower_limit >> 5;483uint upper_position = upper_limit & 0x1f;484uint lower_position = lower_limit & 0x1f;485486uint mask = (((uint)1) << upper_position) - 1;487488while (upper_idx > lower_idx) {489res_mask[upper_idx--] |= mask;490mask = (uint)-1;491}492493mask -= (((uint)1) << lower_position) - 1;494res_mask[upper_idx] |= mask;495496for (j = cyclemasksize-1; j >= 0; j--) {497formatlen =498sprintf(&resource_mask[templen], "0x%08x%s", res_mask[j], j > 0 ? ", " : "");499templen += formatlen;500}501502resource_mask[templen++] = ')';503resource_mask[templen++] = ')';504last_comma = &resource_mask[templen];505resource_mask[templen++] = ',';506resource_mask[templen++] = '\n';507}508509resource_mask[templen] = 0;510if (last_comma) {511last_comma[0] = ' ';512}513514// See if the same string is in the table515int ndx = pipeline_res_mask.index(resource_mask);516517// No, add it to the table518if (ndx < 0) {519pipeline_res_mask.addName(resource_mask);520ndx = pipeline_res_mask.index(resource_mask);521522if (strlen(resource_mask) > 0)523fprintf(fp_cpp, "static const Pipeline_Use_Element pipeline_res_mask_%03d[%d] = {\n%s};\n\n",524ndx+1, element_count, resource_mask);525526char* args = new char [9 + 2*masklen + maskdigit];527528sprintf(args, "0x%0*x, 0x%0*x, %*d",529masklen, resources_used,530masklen, resources_used_exclusively,531maskdigit, element_count);532533pipeline_res_args.addName(args);534}535else {536delete [] resource_mask;537}538539delete [] res_mask;540//delete [] res_masks;541542return (ndx);543}544545void ArchDesc::build_pipe_classes(FILE *fp_cpp) {546const char *classname;547const char *resourcename;548int resourcenamelen = 0;549NameList pipeline_reads;550NameList pipeline_res_stages;551NameList pipeline_res_cycles;552NameList pipeline_res_masks;553NameList pipeline_res_args;554const int default_latency = 1;555const int non_operand_latency = 0;556const int node_latency = 0;557558if (!_pipeline) {559fprintf(fp_cpp, "uint Node::latency(uint i) const {\n");560fprintf(fp_cpp, " // assert(false, \"pipeline functionality is not defined\");\n");561fprintf(fp_cpp, " return %d;\n", non_operand_latency);562fprintf(fp_cpp, "}\n");563return;564}565566fprintf(fp_cpp, "\n");567fprintf(fp_cpp, "//------------------Pipeline Methods-----------------------------------------\n");568fprintf(fp_cpp, "#ifndef PRODUCT\n");569fprintf(fp_cpp, "const char * Pipeline::stageName(uint s) {\n");570fprintf(fp_cpp, " static const char * const _stage_names[] = {\n");571fprintf(fp_cpp, " \"undefined\"");572573for (int s = 0; s < _pipeline->_stagecnt; s++)574fprintf(fp_cpp, ", \"%s\"", _pipeline->_stages.name(s));575576fprintf(fp_cpp, "\n };\n\n");577fprintf(fp_cpp, " return (s <= %d ? _stage_names[s] : \"???\");\n",578_pipeline->_stagecnt);579fprintf(fp_cpp, "}\n");580fprintf(fp_cpp, "#endif\n\n");581582fprintf(fp_cpp, "uint Pipeline::functional_unit_latency(uint start, const Pipeline *pred) const {\n");583fprintf(fp_cpp, " // See if the functional units overlap\n");584#if 0585fprintf(fp_cpp, "\n#ifndef PRODUCT\n");586fprintf(fp_cpp, " if (TraceOptoOutput) {\n");587fprintf(fp_cpp, " tty->print(\"# functional_unit_latency: start == %%d, this->exclusively == 0x%%03x, pred->exclusively == 0x%%03x\\n\", start, resourcesUsedExclusively(), pred->resourcesUsedExclusively());\n");588fprintf(fp_cpp, " }\n");589fprintf(fp_cpp, "#endif\n\n");590#endif591fprintf(fp_cpp, " uint mask = resourcesUsedExclusively() & pred->resourcesUsedExclusively();\n");592fprintf(fp_cpp, " if (mask == 0)\n return (start);\n\n");593#if 0594fprintf(fp_cpp, "\n#ifndef PRODUCT\n");595fprintf(fp_cpp, " if (TraceOptoOutput) {\n");596fprintf(fp_cpp, " tty->print(\"# functional_unit_latency: mask == 0x%%x\\n\", mask);\n");597fprintf(fp_cpp, " }\n");598fprintf(fp_cpp, "#endif\n\n");599#endif600fprintf(fp_cpp, " for (uint i = 0; i < pred->resourceUseCount(); i++) {\n");601fprintf(fp_cpp, " const Pipeline_Use_Element *predUse = pred->resourceUseElement(i);\n");602fprintf(fp_cpp, " if (predUse->multiple())\n");603fprintf(fp_cpp, " continue;\n\n");604fprintf(fp_cpp, " for (uint j = 0; j < resourceUseCount(); j++) {\n");605fprintf(fp_cpp, " const Pipeline_Use_Element *currUse = resourceUseElement(j);\n");606fprintf(fp_cpp, " if (currUse->multiple())\n");607fprintf(fp_cpp, " continue;\n\n");608fprintf(fp_cpp, " if (predUse->used() & currUse->used()) {\n");609fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask x = predUse->mask();\n");610fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask y = currUse->mask();\n\n");611fprintf(fp_cpp, " for ( y <<= start; x.overlaps(y); start++ )\n");612fprintf(fp_cpp, " y <<= 1;\n");613fprintf(fp_cpp, " }\n");614fprintf(fp_cpp, " }\n");615fprintf(fp_cpp, " }\n\n");616fprintf(fp_cpp, " // There is the potential for overlap\n");617fprintf(fp_cpp, " return (start);\n");618fprintf(fp_cpp, "}\n\n");619fprintf(fp_cpp, "// The following two routines assume that the root Pipeline_Use entity\n");620fprintf(fp_cpp, "// consists of exactly 1 element for each functional unit\n");621fprintf(fp_cpp, "// start is relative to the current cycle; used for latency-based info\n");622fprintf(fp_cpp, "uint Pipeline_Use::full_latency(uint delay, const Pipeline_Use &pred) const {\n");623fprintf(fp_cpp, " for (uint i = 0; i < pred._count; i++) {\n");624fprintf(fp_cpp, " const Pipeline_Use_Element *predUse = pred.element(i);\n");625fprintf(fp_cpp, " if (predUse->_multiple) {\n");626fprintf(fp_cpp, " uint min_delay = %d;\n",627_pipeline->_maxcycleused+1);628fprintf(fp_cpp, " // Multiple possible functional units, choose first unused one\n");629fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");630fprintf(fp_cpp, " const Pipeline_Use_Element *currUse = element(j);\n");631fprintf(fp_cpp, " uint curr_delay = delay;\n");632fprintf(fp_cpp, " if (predUse->_used & currUse->_used) {\n");633fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask x = predUse->_mask;\n");634fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask y = currUse->_mask;\n\n");635fprintf(fp_cpp, " for ( y <<= curr_delay; x.overlaps(y); curr_delay++ )\n");636fprintf(fp_cpp, " y <<= 1;\n");637fprintf(fp_cpp, " }\n");638fprintf(fp_cpp, " if (min_delay > curr_delay)\n min_delay = curr_delay;\n");639fprintf(fp_cpp, " }\n");640fprintf(fp_cpp, " if (delay < min_delay)\n delay = min_delay;\n");641fprintf(fp_cpp, " }\n");642fprintf(fp_cpp, " else {\n");643fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");644fprintf(fp_cpp, " const Pipeline_Use_Element *currUse = element(j);\n");645fprintf(fp_cpp, " if (predUse->_used & currUse->_used) {\n");646fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask x = predUse->_mask;\n");647fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask y = currUse->_mask;\n\n");648fprintf(fp_cpp, " for ( y <<= delay; x.overlaps(y); delay++ )\n");649fprintf(fp_cpp, " y <<= 1;\n");650fprintf(fp_cpp, " }\n");651fprintf(fp_cpp, " }\n");652fprintf(fp_cpp, " }\n");653fprintf(fp_cpp, " }\n\n");654fprintf(fp_cpp, " return (delay);\n");655fprintf(fp_cpp, "}\n\n");656fprintf(fp_cpp, "void Pipeline_Use::add_usage(const Pipeline_Use &pred) {\n");657fprintf(fp_cpp, " for (uint i = 0; i < pred._count; i++) {\n");658fprintf(fp_cpp, " const Pipeline_Use_Element *predUse = pred.element(i);\n");659fprintf(fp_cpp, " if (predUse->_multiple) {\n");660fprintf(fp_cpp, " // Multiple possible functional units, choose first unused one\n");661fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");662fprintf(fp_cpp, " Pipeline_Use_Element *currUse = element(j);\n");663fprintf(fp_cpp, " if ( !predUse->_mask.overlaps(currUse->_mask) ) {\n");664fprintf(fp_cpp, " currUse->_used |= (1 << j);\n");665fprintf(fp_cpp, " _resources_used |= (1 << j);\n");666fprintf(fp_cpp, " currUse->_mask.Or(predUse->_mask);\n");667fprintf(fp_cpp, " break;\n");668fprintf(fp_cpp, " }\n");669fprintf(fp_cpp, " }\n");670fprintf(fp_cpp, " }\n");671fprintf(fp_cpp, " else {\n");672fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");673fprintf(fp_cpp, " Pipeline_Use_Element *currUse = element(j);\n");674fprintf(fp_cpp, " currUse->_used |= (1 << j);\n");675fprintf(fp_cpp, " _resources_used |= (1 << j);\n");676fprintf(fp_cpp, " currUse->_mask.Or(predUse->_mask);\n");677fprintf(fp_cpp, " }\n");678fprintf(fp_cpp, " }\n");679fprintf(fp_cpp, " }\n");680fprintf(fp_cpp, "}\n\n");681682fprintf(fp_cpp, "uint Pipeline::operand_latency(uint opnd, const Pipeline *pred) const {\n");683fprintf(fp_cpp, " int const default_latency = 1;\n");684fprintf(fp_cpp, "\n");685#if 0686fprintf(fp_cpp, "#ifndef PRODUCT\n");687fprintf(fp_cpp, " if (TraceOptoOutput) {\n");688fprintf(fp_cpp, " tty->print(\"# operand_latency(%%d), _read_stage_count = %%d\\n\", opnd, _read_stage_count);\n");689fprintf(fp_cpp, " }\n");690fprintf(fp_cpp, "#endif\n\n");691#endif692fprintf(fp_cpp, " assert(this, \"NULL pipeline info\");\n");693fprintf(fp_cpp, " assert(pred, \"NULL predecessor pipline info\");\n\n");694fprintf(fp_cpp, " if (pred->hasFixedLatency())\n return (pred->fixedLatency());\n\n");695fprintf(fp_cpp, " // If this is not an operand, then assume a dependence with 0 latency\n");696fprintf(fp_cpp, " if (opnd > _read_stage_count)\n return (0);\n\n");697fprintf(fp_cpp, " uint writeStage = pred->_write_stage;\n");698fprintf(fp_cpp, " uint readStage = _read_stages[opnd-1];\n");699#if 0700fprintf(fp_cpp, "\n#ifndef PRODUCT\n");701fprintf(fp_cpp, " if (TraceOptoOutput) {\n");702fprintf(fp_cpp, " tty->print(\"# operand_latency: writeStage=%%s readStage=%%s, opnd=%%d\\n\", stageName(writeStage), stageName(readStage), opnd);\n");703fprintf(fp_cpp, " }\n");704fprintf(fp_cpp, "#endif\n\n");705#endif706fprintf(fp_cpp, "\n");707fprintf(fp_cpp, " if (writeStage == stage_undefined || readStage == stage_undefined)\n");708fprintf(fp_cpp, " return (default_latency);\n");709fprintf(fp_cpp, "\n");710fprintf(fp_cpp, " int delta = writeStage - readStage;\n");711fprintf(fp_cpp, " if (delta < 0) delta = 0;\n\n");712#if 0713fprintf(fp_cpp, "\n#ifndef PRODUCT\n");714fprintf(fp_cpp, " if (TraceOptoOutput) {\n");715fprintf(fp_cpp, " tty->print(\"# operand_latency: delta=%%d\\n\", delta);\n");716fprintf(fp_cpp, " }\n");717fprintf(fp_cpp, "#endif\n\n");718#endif719fprintf(fp_cpp, " return (delta);\n");720fprintf(fp_cpp, "}\n\n");721722if (!_pipeline)723/* Do Nothing */;724725else if (_pipeline->_maxcycleused <= 32) {726fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");727fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask & in2._mask);\n");728fprintf(fp_cpp, "}\n\n");729fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");730fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask | in2._mask);\n");731fprintf(fp_cpp, "}\n\n");732}733else {734uint l;735uint masklen = (_pipeline->_maxcycleused + 31) >> 5;736fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");737fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(");738for (l = 1; l <= masklen; l++)739fprintf(fp_cpp, "in1._mask%d & in2._mask%d%s\n", l, l, l < masklen ? ", " : "");740fprintf(fp_cpp, ");\n");741fprintf(fp_cpp, "}\n\n");742fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");743fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(");744for (l = 1; l <= masklen; l++)745fprintf(fp_cpp, "in1._mask%d | in2._mask%d%s", l, l, l < masklen ? ", " : "");746fprintf(fp_cpp, ");\n");747fprintf(fp_cpp, "}\n\n");748fprintf(fp_cpp, "void Pipeline_Use_Cycle_Mask::Or(const Pipeline_Use_Cycle_Mask &in2) {\n ");749for (l = 1; l <= masklen; l++)750fprintf(fp_cpp, " _mask%d |= in2._mask%d;", l, l);751fprintf(fp_cpp, "\n}\n\n");752}753754/* Get the length of all the resource names */755for (_pipeline->_reslist.reset(), resourcenamelen = 0;756(resourcename = _pipeline->_reslist.iter()) != NULL;757resourcenamelen += (int)strlen(resourcename));758759// Create the pipeline class description760761fprintf(fp_cpp, "static const Pipeline pipeline_class_Zero_Instructions(0, 0, true, 0, 0, false, false, false, false, NULL, NULL, NULL, Pipeline_Use(0, 0, 0, NULL));\n\n");762fprintf(fp_cpp, "static const Pipeline pipeline_class_Unknown_Instructions(0, 0, true, 0, 0, false, true, true, false, NULL, NULL, NULL, Pipeline_Use(0, 0, 0, NULL));\n\n");763764fprintf(fp_cpp, "const Pipeline_Use_Element Pipeline_Use::elaborated_elements[%d] = {\n", _pipeline->_rescount);765for (int i1 = 0; i1 < _pipeline->_rescount; i1++) {766fprintf(fp_cpp, " Pipeline_Use_Element(0, %d, %d, false, Pipeline_Use_Cycle_Mask(", i1, i1);767uint masklen = (_pipeline->_maxcycleused + 31) >> 5;768for (int i2 = masklen-1; i2 >= 0; i2--)769fprintf(fp_cpp, "0%s", i2 > 0 ? ", " : "");770fprintf(fp_cpp, "))%s\n", i1 < (_pipeline->_rescount-1) ? "," : "");771}772fprintf(fp_cpp, "};\n\n");773774fprintf(fp_cpp, "const Pipeline_Use Pipeline_Use::elaborated_use(0, 0, %d, (Pipeline_Use_Element *)&elaborated_elements[0]);\n\n",775_pipeline->_rescount);776777for (_pipeline->_classlist.reset(); (classname = _pipeline->_classlist.iter()) != NULL; ) {778fprintf(fp_cpp, "\n");779fprintf(fp_cpp, "// Pipeline Class \"%s\"\n", classname);780PipeClassForm *pipeclass = _pipeline->_classdict[classname]->is_pipeclass();781int maxWriteStage = -1;782int maxMoreInstrs = 0;783int paramcount = 0;784int i = 0;785const char *paramname;786int resource_count = (_pipeline->_rescount + 3) >> 2;787788// Scan the operands, looking for last output stage and number of inputs789for (pipeclass->_parameters.reset(); (paramname = pipeclass->_parameters.iter()) != NULL; ) {790const PipeClassOperandForm *pipeopnd =791(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];792if (pipeopnd) {793if (pipeopnd->_iswrite) {794int stagenum = _pipeline->_stages.index(pipeopnd->_stage);795int moreinsts = pipeopnd->_more_instrs;796if ((maxWriteStage+maxMoreInstrs) < (stagenum+moreinsts)) {797maxWriteStage = stagenum;798maxMoreInstrs = moreinsts;799}800}801}802803if (i++ > 0 || (pipeopnd && !pipeopnd->isWrite()))804paramcount++;805}806807// Create the list of stages for the operands that are read808// Note that we will build a NameList to reduce the number of copies809810int pipeline_reads_index = pipeline_reads_initializer(fp_cpp, pipeline_reads, pipeclass);811812int pipeline_res_stages_index = pipeline_res_stages_initializer(813fp_cpp, _pipeline, pipeline_res_stages, pipeclass);814815int pipeline_res_cycles_index = pipeline_res_cycles_initializer(816fp_cpp, _pipeline, pipeline_res_cycles, pipeclass);817818int pipeline_res_mask_index = pipeline_res_mask_initializer(819fp_cpp, _pipeline, pipeline_res_masks, pipeline_res_args, pipeclass);820821#if 0822// Process the Resources823const PipeClassResourceForm *piperesource;824825unsigned resources_used = 0;826unsigned exclusive_resources_used = 0;827unsigned resource_groups = 0;828for (pipeclass->_resUsage.reset();829(piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {830int used_mask = _pipeline->_resdict[piperesource->_resource]->is_resource()->mask();831if (used_mask)832resource_groups++;833resources_used |= used_mask;834if ((used_mask & (used_mask-1)) == 0)835exclusive_resources_used |= used_mask;836}837838if (resource_groups > 0) {839fprintf(fp_cpp, "static const uint pipeline_res_or_masks_%03d[%d] = {",840pipeclass->_num, resource_groups);841for (pipeclass->_resUsage.reset(), i = 1;842(piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL;843i++ ) {844int used_mask = _pipeline->_resdict[piperesource->_resource]->is_resource()->mask();845if (used_mask) {846fprintf(fp_cpp, " 0x%0*x%c", resource_count, used_mask, i < (int)resource_groups ? ',' : ' ');847}848}849fprintf(fp_cpp, "};\n\n");850}851#endif852853// Create the pipeline class description854fprintf(fp_cpp, "static const Pipeline pipeline_class_%03d(",855pipeclass->_num);856if (maxWriteStage < 0)857fprintf(fp_cpp, "(uint)stage_undefined");858else if (maxMoreInstrs == 0)859fprintf(fp_cpp, "(uint)stage_%s", _pipeline->_stages.name(maxWriteStage));860else861fprintf(fp_cpp, "((uint)stage_%s)+%d", _pipeline->_stages.name(maxWriteStage), maxMoreInstrs);862fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s, %s,\n",863paramcount,864pipeclass->hasFixedLatency() ? "true" : "false",865pipeclass->fixedLatency(),866pipeclass->InstructionCount(),867pipeclass->hasBranchDelay() ? "true" : "false",868pipeclass->hasMultipleBundles() ? "true" : "false",869pipeclass->forceSerialization() ? "true" : "false",870pipeclass->mayHaveNoCode() ? "true" : "false" );871if (paramcount > 0) {872fprintf(fp_cpp, "\n (enum machPipelineStages * const) pipeline_reads_%03d,\n ",873pipeline_reads_index+1);874}875else876fprintf(fp_cpp, " NULL,");877fprintf(fp_cpp, " (enum machPipelineStages * const) pipeline_res_stages_%03d,\n",878pipeline_res_stages_index+1);879fprintf(fp_cpp, " (uint * const) pipeline_res_cycles_%03d,\n",880pipeline_res_cycles_index+1);881fprintf(fp_cpp, " Pipeline_Use(%s, (Pipeline_Use_Element *)",882pipeline_res_args.name(pipeline_res_mask_index));883if (strlen(pipeline_res_masks.name(pipeline_res_mask_index)) > 0)884fprintf(fp_cpp, "&pipeline_res_mask_%03d[0]",885pipeline_res_mask_index+1);886else887fprintf(fp_cpp, "NULL");888fprintf(fp_cpp, "));\n");889}890891// Generate the Node::latency method if _pipeline defined892fprintf(fp_cpp, "\n");893fprintf(fp_cpp, "//------------------Inter-Instruction Latency--------------------------------\n");894fprintf(fp_cpp, "uint Node::latency(uint i) {\n");895if (_pipeline) {896#if 0897fprintf(fp_cpp, "#ifndef PRODUCT\n");898fprintf(fp_cpp, " if (TraceOptoOutput) {\n");899fprintf(fp_cpp, " tty->print(\"# %%4d->latency(%%d)\\n\", _idx, i);\n");900fprintf(fp_cpp, " }\n");901fprintf(fp_cpp, "#endif\n");902#endif903fprintf(fp_cpp, " uint j;\n");904fprintf(fp_cpp, " // verify in legal range for inputs\n");905fprintf(fp_cpp, " assert(i < len(), \"index not in range\");\n\n");906fprintf(fp_cpp, " // verify input is not null\n");907fprintf(fp_cpp, " Node *pred = in(i);\n");908fprintf(fp_cpp, " if (!pred)\n return %d;\n\n",909non_operand_latency);910fprintf(fp_cpp, " if (pred->is_Proj())\n pred = pred->in(0);\n\n");911fprintf(fp_cpp, " // if either node does not have pipeline info, use default\n");912fprintf(fp_cpp, " const Pipeline *predpipe = pred->pipeline();\n");913fprintf(fp_cpp, " assert(predpipe, \"no predecessor pipeline info\");\n\n");914fprintf(fp_cpp, " if (predpipe->hasFixedLatency())\n return predpipe->fixedLatency();\n\n");915fprintf(fp_cpp, " const Pipeline *currpipe = pipeline();\n");916fprintf(fp_cpp, " assert(currpipe, \"no pipeline info\");\n\n");917fprintf(fp_cpp, " if (!is_Mach())\n return %d;\n\n",918node_latency);919fprintf(fp_cpp, " const MachNode *m = as_Mach();\n");920fprintf(fp_cpp, " j = m->oper_input_base();\n");921fprintf(fp_cpp, " if (i < j)\n return currpipe->functional_unit_latency(%d, predpipe);\n\n",922non_operand_latency);923fprintf(fp_cpp, " // determine which operand this is in\n");924fprintf(fp_cpp, " uint n = m->num_opnds();\n");925fprintf(fp_cpp, " int delta = %d;\n\n",926non_operand_latency);927fprintf(fp_cpp, " uint k;\n");928fprintf(fp_cpp, " for (k = 1; k < n; k++) {\n");929fprintf(fp_cpp, " j += m->_opnds[k]->num_edges();\n");930fprintf(fp_cpp, " if (i < j)\n");931fprintf(fp_cpp, " break;\n");932fprintf(fp_cpp, " }\n");933fprintf(fp_cpp, " if (k < n)\n");934fprintf(fp_cpp, " delta = currpipe->operand_latency(k,predpipe);\n\n");935fprintf(fp_cpp, " return currpipe->functional_unit_latency(delta, predpipe);\n");936}937else {938fprintf(fp_cpp, " // assert(false, \"pipeline functionality is not defined\");\n");939fprintf(fp_cpp, " return %d;\n",940non_operand_latency);941}942fprintf(fp_cpp, "}\n\n");943944// Output the list of nop nodes945fprintf(fp_cpp, "// Descriptions for emitting different functional unit nops\n");946const char *nop;947int nopcnt = 0;948for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; nopcnt++ );949950fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d]) {\n", nopcnt);951int i = 0;952for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; i++ ) {953fprintf(fp_cpp, " nop_list[%d] = (MachNode *) new %sNode();\n", i, nop);954}955fprintf(fp_cpp, "};\n\n");956fprintf(fp_cpp, "#ifndef PRODUCT\n");957fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n");958fprintf(fp_cpp, " static const char * bundle_flags[] = {\n");959fprintf(fp_cpp, " \"\",\n");960fprintf(fp_cpp, " \"use nop delay\",\n");961fprintf(fp_cpp, " \"use unconditional delay\",\n");962fprintf(fp_cpp, " \"use conditional delay\",\n");963fprintf(fp_cpp, " \"used in conditional delay\",\n");964fprintf(fp_cpp, " \"used in unconditional delay\",\n");965fprintf(fp_cpp, " \"used in all conditional delays\",\n");966fprintf(fp_cpp, " };\n\n");967968fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount);969for (i = 0; i < _pipeline->_rescount; i++)970fprintf(fp_cpp, " \"%s\"%c", _pipeline->_reslist.name(i), i < _pipeline->_rescount-1 ? ',' : ' ');971fprintf(fp_cpp, "};\n\n");972973// See if the same string is in the table974fprintf(fp_cpp, " bool needs_comma = false;\n\n");975fprintf(fp_cpp, " if (_flags) {\n");976fprintf(fp_cpp, " st->print(\"%%s\", bundle_flags[_flags]);\n");977fprintf(fp_cpp, " needs_comma = true;\n");978fprintf(fp_cpp, " };\n");979fprintf(fp_cpp, " if (instr_count()) {\n");980fprintf(fp_cpp, " st->print(\"%%s%%d instr%%s\", needs_comma ? \", \" : \"\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n");981fprintf(fp_cpp, " needs_comma = true;\n");982fprintf(fp_cpp, " };\n");983fprintf(fp_cpp, " uint r = resources_used();\n");984fprintf(fp_cpp, " if (r) {\n");985fprintf(fp_cpp, " st->print(\"%%sresource%%s:\", needs_comma ? \", \" : \"\", (r & (r-1)) != 0 ? \"s\" : \"\");\n");986fprintf(fp_cpp, " for (uint i = 0; i < %d; i++)\n", _pipeline->_rescount);987fprintf(fp_cpp, " if ((r & (1 << i)) != 0)\n");988fprintf(fp_cpp, " st->print(\" %%s\", resource_names[i]);\n");989fprintf(fp_cpp, " needs_comma = true;\n");990fprintf(fp_cpp, " };\n");991fprintf(fp_cpp, " st->print(\"\\n\");\n");992fprintf(fp_cpp, "}\n");993fprintf(fp_cpp, "#endif\n");994}995996// ---------------------------------------------------------------------------997//------------------------------Utilities to build Instruction Classes--------998// ---------------------------------------------------------------------------9991000static void defineOut_RegMask(FILE *fp, const char *node, const char *regMask) {1001fprintf(fp,"const RegMask &%sNode::out_RegMask() const { return (%s); }\n",1002node, regMask);1003}10041005static void print_block_index(FILE *fp, int inst_position) {1006assert( inst_position >= 0, "Instruction number less than zero");1007fprintf(fp, "block_index");1008if( inst_position != 0 ) {1009fprintf(fp, " - %d", inst_position);1010}1011}10121013// Scan the peepmatch and output a test for each instruction1014static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) {1015int parent = -1;1016int inst_position = 0;1017const char* inst_name = NULL;1018int input = 0;1019fprintf(fp, " // Check instruction sub-tree\n");1020pmatch->reset();1021for( pmatch->next_instruction( parent, inst_position, inst_name, input );1022inst_name != NULL;1023pmatch->next_instruction( parent, inst_position, inst_name, input ) ) {1024// If this is not a placeholder1025if( ! pmatch->is_placeholder() ) {1026// Define temporaries 'inst#', based on parent and parent's input index1027if( parent != -1 ) { // root was initialized1028fprintf(fp, " // Identify previous instruction if inside this block\n");1029fprintf(fp, " if( ");1030print_block_index(fp, inst_position);1031fprintf(fp, " > 0 ) {\n Node *n = block->get_node(");1032print_block_index(fp, inst_position);1033fprintf(fp, ");\n inst%d = (n->is_Mach()) ? ", inst_position);1034fprintf(fp, "n->as_Mach() : NULL;\n }\n");1035}10361037// When not the root1038// Test we have the correct instruction by comparing the rule.1039if( parent != -1 ) {1040fprintf(fp, " matches = matches && (inst%d != NULL) && (inst%d->rule() == %s_rule);\n",1041inst_position, inst_position, inst_name);1042}1043} else {1044// Check that user did not try to constrain a placeholder1045assert( ! pconstraint->constrains_instruction(inst_position),1046"fatal(): Can not constrain a placeholder instruction");1047}1048}1049}10501051// Build mapping for register indices, num_edges to input1052static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMatch *pmatch ) {1053int parent = -1;1054int inst_position = 0;1055const char* inst_name = NULL;1056int input = 0;1057fprintf(fp, " // Build map to register info\n");1058pmatch->reset();1059for( pmatch->next_instruction( parent, inst_position, inst_name, input );1060inst_name != NULL;1061pmatch->next_instruction( parent, inst_position, inst_name, input ) ) {1062// If this is not a placeholder1063if( ! pmatch->is_placeholder() ) {1064// Define temporaries 'inst#', based on self's inst_position1065InstructForm *inst = globals[inst_name]->is_instruction();1066if( inst != NULL ) {1067char inst_prefix[] = "instXXXX_";1068sprintf(inst_prefix, "inst%d_", inst_position);1069char receiver[] = "instXXXX->";1070sprintf(receiver, "inst%d->", inst_position);1071inst->index_temps( fp, globals, inst_prefix, receiver );1072}1073}1074}1075}10761077// Generate tests for the constraints1078static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch, PeepConstraint *pconstraint) {1079fprintf(fp, "\n");1080fprintf(fp, " // Check constraints on sub-tree-leaves\n");10811082// Build mapping from num_edges to local variables1083build_instruction_index_mapping( fp, globals, pmatch );10841085// Build constraint tests1086if( pconstraint != NULL ) {1087fprintf(fp, " matches = matches &&");1088bool first_constraint = true;1089while( pconstraint != NULL ) {1090// indentation and connecting '&&'1091const char *indentation = " ";1092fprintf(fp, "\n%s%s", indentation, (!first_constraint ? "&& " : " "));10931094// Only have '==' relation implemented1095if( strcmp(pconstraint->_relation,"==") != 0 ) {1096assert( false, "Unimplemented()" );1097}10981099// LEFT1100int left_index = pconstraint->_left_inst;1101const char *left_op = pconstraint->_left_op;1102// Access info on the instructions whose operands are compared1103InstructForm *inst_left = globals[pmatch->instruction_name(left_index)]->is_instruction();1104assert( inst_left, "Parser should guaranty this is an instruction");1105int left_op_base = inst_left->oper_input_base(globals);1106// Access info on the operands being compared1107int left_op_index = inst_left->operand_position(left_op, Component::USE);1108if( left_op_index == -1 ) {1109left_op_index = inst_left->operand_position(left_op, Component::DEF);1110if( left_op_index == -1 ) {1111left_op_index = inst_left->operand_position(left_op, Component::USE_DEF);1112}1113}1114assert( left_op_index != NameList::Not_in_list, "Did not find operand in instruction");1115ComponentList components_left = inst_left->_components;1116const char *left_comp_type = components_left.at(left_op_index)->_type;1117OpClassForm *left_opclass = globals[left_comp_type]->is_opclass();1118Form::InterfaceType left_interface_type = left_opclass->interface_type(globals);111911201121// RIGHT1122int right_op_index = -1;1123int right_index = pconstraint->_right_inst;1124const char *right_op = pconstraint->_right_op;1125if( right_index != -1 ) { // Match operand1126// Access info on the instructions whose operands are compared1127InstructForm *inst_right = globals[pmatch->instruction_name(right_index)]->is_instruction();1128assert( inst_right, "Parser should guaranty this is an instruction");1129int right_op_base = inst_right->oper_input_base(globals);1130// Access info on the operands being compared1131right_op_index = inst_right->operand_position(right_op, Component::USE);1132if( right_op_index == -1 ) {1133right_op_index = inst_right->operand_position(right_op, Component::DEF);1134if( right_op_index == -1 ) {1135right_op_index = inst_right->operand_position(right_op, Component::USE_DEF);1136}1137}1138assert( right_op_index != NameList::Not_in_list, "Did not find operand in instruction");1139ComponentList components_right = inst_right->_components;1140const char *right_comp_type = components_right.at(right_op_index)->_type;1141OpClassForm *right_opclass = globals[right_comp_type]->is_opclass();1142Form::InterfaceType right_interface_type = right_opclass->interface_type(globals);1143assert( right_interface_type == left_interface_type, "Both must be same interface");11441145} else { // Else match register1146// assert( false, "should be a register" );1147}11481149//1150// Check for equivalence1151//1152// fprintf(fp, "(inst%d->_opnds[%d]->reg(ra_,inst%d%s) /* %d.%s */ == /* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)",1153// left_index, left_op_index, left_index, left_reg_index, left_index, left_op1154// right_index, right_op, right_index, right_op_index, right_index, right_reg_index);1155// fprintf(fp, ")");1156//1157switch( left_interface_type ) {1158case Form::register_interface: {1159// Check that they are allocated to the same register1160// Need parameter for index position if not result operand1161char left_reg_index[] = ",instXXXX_idxXXXX";1162if( left_op_index != 0 ) {1163assert( (left_index <= 9999) && (left_op_index <= 9999), "exceed string size");1164// Must have index into operands1165sprintf(left_reg_index,",inst%d_idx%d", (int)left_index, left_op_index);1166} else {1167strcpy(left_reg_index, "");1168}1169fprintf(fp, "(inst%d->_opnds[%d]->reg(ra_,inst%d%s) /* %d.%s */",1170left_index, left_op_index, left_index, left_reg_index, left_index, left_op );1171fprintf(fp, " == ");11721173if( right_index != -1 ) {1174char right_reg_index[18] = ",instXXXX_idxXXXX";1175if( right_op_index != 0 ) {1176assert( (right_index <= 9999) && (right_op_index <= 9999), "exceed string size");1177// Must have index into operands1178sprintf(right_reg_index,",inst%d_idx%d", (int)right_index, right_op_index);1179} else {1180strcpy(right_reg_index, "");1181}1182fprintf(fp, "/* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)",1183right_index, right_op, right_index, right_op_index, right_index, right_reg_index );1184} else {1185fprintf(fp, "%s_enc", right_op );1186}1187fprintf(fp,")");1188break;1189}1190case Form::constant_interface: {1191// Compare the '->constant()' values1192fprintf(fp, "(inst%d->_opnds[%d]->constant() /* %d.%s */",1193left_index, left_op_index, left_index, left_op );1194fprintf(fp, " == ");1195fprintf(fp, "/* %d.%s */ inst%d->_opnds[%d]->constant())",1196right_index, right_op, right_index, right_op_index );1197break;1198}1199case Form::memory_interface: {1200// Compare 'base', 'index', 'scale', and 'disp'1201// base1202fprintf(fp, "( \n");1203fprintf(fp, " (inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d) /* %d.%s$$base */",1204left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );1205fprintf(fp, " == ");1206fprintf(fp, "/* %d.%s$$base */ inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d)) &&\n",1207right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );1208// index1209fprintf(fp, " (inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d) /* %d.%s$$index */",1210left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );1211fprintf(fp, " == ");1212fprintf(fp, "/* %d.%s$$index */ inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d)) &&\n",1213right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );1214// scale1215fprintf(fp, " (inst%d->_opnds[%d]->scale() /* %d.%s$$scale */",1216left_index, left_op_index, left_index, left_op );1217fprintf(fp, " == ");1218fprintf(fp, "/* %d.%s$$scale */ inst%d->_opnds[%d]->scale()) &&\n",1219right_index, right_op, right_index, right_op_index );1220// disp1221fprintf(fp, " (inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d) /* %d.%s$$disp */",1222left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );1223fprintf(fp, " == ");1224fprintf(fp, "/* %d.%s$$disp */ inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d))\n",1225right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );1226fprintf(fp, ") \n");1227break;1228}1229case Form::conditional_interface: {1230// Compare the condition code being tested1231assert( false, "Unimplemented()" );1232break;1233}1234default: {1235assert( false, "ShouldNotReachHere()" );1236break;1237}1238}12391240// Advance to next constraint1241pconstraint = pconstraint->next();1242first_constraint = false;1243}12441245fprintf(fp, ";\n");1246}1247}12481249// // EXPERIMENTAL -- TEMPORARY code1250// static Form::DataType get_operand_type(FormDict &globals, InstructForm *instr, const char *op_name ) {1251// int op_index = instr->operand_position(op_name, Component::USE);1252// if( op_index == -1 ) {1253// op_index = instr->operand_position(op_name, Component::DEF);1254// if( op_index == -1 ) {1255// op_index = instr->operand_position(op_name, Component::USE_DEF);1256// }1257// }1258// assert( op_index != NameList::Not_in_list, "Did not find operand in instruction");1259//1260// ComponentList components_right = instr->_components;1261// char *right_comp_type = components_right.at(op_index)->_type;1262// OpClassForm *right_opclass = globals[right_comp_type]->is_opclass();1263// Form::InterfaceType right_interface_type = right_opclass->interface_type(globals);1264//1265// return;1266// }12671268// Construct the new sub-tree1269static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch, PeepConstraint *pconstraint, PeepReplace *preplace, int max_position ) {1270fprintf(fp, " // IF instructions and constraints matched\n");1271fprintf(fp, " if( matches ) {\n");1272fprintf(fp, " // generate the new sub-tree\n");1273fprintf(fp, " assert( true, \"Debug stopping point\");\n");1274if( preplace != NULL ) {1275// Get the root of the new sub-tree1276const char *root_inst = NULL;1277preplace->next_instruction(root_inst);1278InstructForm *root_form = globals[root_inst]->is_instruction();1279assert( root_form != NULL, "Replacement instruction was not previously defined");1280fprintf(fp, " %sNode *root = new %sNode();\n", root_inst, root_inst);12811282int inst_num;1283const char *op_name;1284int opnds_index = 0; // define result operand1285// Then install the use-operands for the new sub-tree1286// preplace->reset(); // reset breaks iteration1287for( preplace->next_operand( inst_num, op_name );1288op_name != NULL;1289preplace->next_operand( inst_num, op_name ) ) {1290InstructForm *inst_form;1291inst_form = globals[pmatch->instruction_name(inst_num)]->is_instruction();1292assert( inst_form, "Parser should guaranty this is an instruction");1293int inst_op_num = inst_form->operand_position(op_name, Component::USE);1294if( inst_op_num == NameList::Not_in_list )1295inst_op_num = inst_form->operand_position(op_name, Component::USE_DEF);1296assert( inst_op_num != NameList::Not_in_list, "Did not find operand as USE");1297// find the name of the OperandForm from the local name1298const Form *form = inst_form->_localNames[op_name];1299OperandForm *op_form = form->is_operand();1300if( opnds_index == 0 ) {1301// Initial setup of new instruction1302fprintf(fp, " // ----- Initial setup -----\n");1303//1304// Add control edge for this node1305fprintf(fp, " root->add_req(_in[0]); // control edge\n");1306// Add unmatched edges from root of match tree1307int op_base = root_form->oper_input_base(globals);1308for( int unmatched_edge = 1; unmatched_edge < op_base; ++unmatched_edge ) {1309fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",1310inst_num, unmatched_edge);1311}1312// If new instruction captures bottom type1313if( root_form->captures_bottom_type(globals) ) {1314// Get bottom type from instruction whose result we are replacing1315fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);1316}1317// Define result register and result operand1318fprintf(fp, " ra_->add_reference(root, inst%d);\n", inst_num);1319fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num);1320fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num);1321fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(); // result\n", inst_num);1322fprintf(fp, " // ----- Done with initial setup -----\n");1323} else {1324if( (op_form == NULL) || (op_form->is_base_constant(globals) == Form::none) ) {1325// Do not have ideal edges for constants after matching1326fprintf(fp, " for( unsigned x%d = inst%d_idx%d; x%d < inst%d_idx%d; x%d++ )\n",1327inst_op_num, inst_num, inst_op_num,1328inst_op_num, inst_num, inst_op_num+1, inst_op_num );1329fprintf(fp, " root->add_req( inst%d->in(x%d) );\n",1330inst_num, inst_op_num );1331} else {1332fprintf(fp, " // no ideal edge for constants after matching\n");1333}1334fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone();\n",1335opnds_index, inst_num, inst_op_num );1336}1337++opnds_index;1338}1339}else {1340// Replacing subtree with empty-tree1341assert( false, "ShouldNotReachHere();");1342}13431344// Return the new sub-tree1345fprintf(fp, " deleted = %d;\n", max_position+1 /*zero to one based*/);1346fprintf(fp, " return root; // return new root;\n");1347fprintf(fp, " }\n");1348}134913501351// Define the Peephole method for an instruction node1352void ArchDesc::definePeephole(FILE *fp, InstructForm *node) {1353// Generate Peephole function header1354fprintf(fp, "MachNode *%sNode::peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted) {\n", node->_ident);1355fprintf(fp, " bool matches = true;\n");13561357// Identify the maximum instruction position,1358// generate temporaries that hold current instruction1359//1360// MachNode *inst0 = NULL;1361// ...1362// MachNode *instMAX = NULL;1363//1364int max_position = 0;1365Peephole *peep;1366for( peep = node->peepholes(); peep != NULL; peep = peep->next() ) {1367PeepMatch *pmatch = peep->match();1368assert( pmatch != NULL, "fatal(), missing peepmatch rule");1369if( max_position < pmatch->max_position() ) max_position = pmatch->max_position();1370}1371for( int i = 0; i <= max_position; ++i ) {1372if( i == 0 ) {1373fprintf(fp, " MachNode *inst0 = this;\n");1374} else {1375fprintf(fp, " MachNode *inst%d = NULL;\n", i);1376}1377}13781379// For each peephole rule in architecture description1380// Construct a test for the desired instruction sub-tree1381// then check the constraints1382// If these match, Generate the new subtree1383for( peep = node->peepholes(); peep != NULL; peep = peep->next() ) {1384int peephole_number = peep->peephole_number();1385PeepMatch *pmatch = peep->match();1386PeepConstraint *pconstraint = peep->constraints();1387PeepReplace *preplace = peep->replacement();13881389// Root of this peephole is the current MachNode1390assert( true, // %%name?%% strcmp( node->_ident, pmatch->name(0) ) == 0,1391"root of PeepMatch does not match instruction");13921393// Make each peephole rule individually selectable1394fprintf(fp, " if( (OptoPeepholeAt == -1) || (OptoPeepholeAt==%d) ) {\n", peephole_number);1395fprintf(fp, " matches = true;\n");1396// Scan the peepmatch and output a test for each instruction1397check_peepmatch_instruction_sequence( fp, pmatch, pconstraint );13981399// Check constraints and build replacement inside scope1400fprintf(fp, " // If instruction subtree matches\n");1401fprintf(fp, " if( matches ) {\n");14021403// Generate tests for the constraints1404check_peepconstraints( fp, _globalNames, pmatch, pconstraint );14051406// Construct the new sub-tree1407generate_peepreplace( fp, _globalNames, pmatch, pconstraint, preplace, max_position );14081409// End of scope for this peephole's constraints1410fprintf(fp, " }\n");1411// Closing brace '}' to make each peephole rule individually selectable1412fprintf(fp, " } // end of peephole rule #%d\n", peephole_number);1413fprintf(fp, "\n");1414}14151416fprintf(fp, " return NULL; // No peephole rules matched\n");1417fprintf(fp, "}\n");1418fprintf(fp, "\n");1419}14201421// Define the Expand method for an instruction node1422void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {1423unsigned cnt = 0; // Count nodes we have expand into1424unsigned i;14251426// Generate Expand function header1427fprintf(fp, "MachNode* %sNode::Expand(State* state, Node_List& proj_list, Node* mem) {\n", node->_ident);1428fprintf(fp, " Compile* C = Compile::current();\n");1429// Generate expand code1430if( node->expands() ) {1431const char *opid;1432int new_pos, exp_pos;1433const char *new_id = NULL;1434const Form *frm = NULL;1435InstructForm *new_inst = NULL;1436OperandForm *new_oper = NULL;1437unsigned numo = node->num_opnds() +1438node->_exprule->_newopers.count();14391440// If necessary, generate any operands created in expand rule1441if (node->_exprule->_newopers.count()) {1442for(node->_exprule->_newopers.reset();1443(new_id = node->_exprule->_newopers.iter()) != NULL; cnt++) {1444frm = node->_localNames[new_id];1445assert(frm, "Invalid entry in new operands list of expand rule");1446new_oper = frm->is_operand();1447char *tmp = (char *)node->_exprule->_newopconst[new_id];1448if (tmp == NULL) {1449fprintf(fp," MachOper *op%d = new %sOper();\n",1450cnt, new_oper->_ident);1451}1452else {1453fprintf(fp," MachOper *op%d = new %sOper(%s);\n",1454cnt, new_oper->_ident, tmp);1455}1456}1457}1458cnt = 0;1459// Generate the temps to use for DAG building1460for(i = 0; i < numo; i++) {1461if (i < node->num_opnds()) {1462fprintf(fp," MachNode *tmp%d = this;\n", i);1463}1464else {1465fprintf(fp," MachNode *tmp%d = NULL;\n", i);1466}1467}1468// Build mapping from num_edges to local variables1469fprintf(fp," unsigned num0 = 0;\n");1470for( i = 1; i < node->num_opnds(); i++ ) {1471fprintf(fp," unsigned num%d = opnd_array(%d)->num_edges();\n",i,i);1472}14731474// Build a mapping from operand index to input edges1475fprintf(fp," unsigned idx0 = oper_input_base();\n");14761477// The order in which the memory input is added to a node is very1478// strange. Store nodes get a memory input before Expand is1479// called and other nodes get it afterwards or before depending on1480// match order so oper_input_base is wrong during expansion. This1481// code adjusts it so that expansion will work correctly.1482int has_memory_edge = node->_matrule->needs_ideal_memory_edge(_globalNames);1483if (has_memory_edge) {1484fprintf(fp," if (mem == (Node*)1) {\n");1485fprintf(fp," idx0--; // Adjust base because memory edge hasn't been inserted yet\n");1486fprintf(fp," }\n");1487}14881489for( i = 0; i < node->num_opnds(); i++ ) {1490fprintf(fp," unsigned idx%d = idx%d + num%d;\n",1491i+1,i,i);1492}14931494// Declare variable to hold root of expansion1495fprintf(fp," MachNode *result = NULL;\n");14961497// Iterate over the instructions 'node' expands into1498ExpandRule *expand = node->_exprule;1499NameAndList *expand_instr = NULL;1500for (expand->reset_instructions();1501(expand_instr = expand->iter_instructions()) != NULL; cnt++) {1502new_id = expand_instr->name();15031504InstructForm* expand_instruction = (InstructForm*)globalAD->globalNames()[new_id];15051506if (!expand_instruction) {1507globalAD->syntax_err(node->_linenum, "In %s: instruction %s used in expand not declared\n",1508node->_ident, new_id);1509continue;1510}15111512// Build the node for the instruction1513fprintf(fp,"\n %sNode *n%d = new %sNode();\n", new_id, cnt, new_id);1514// Add control edge for this node1515fprintf(fp," n%d->add_req(_in[0]);\n", cnt);1516// Build the operand for the value this node defines.1517Form *form = (Form*)_globalNames[new_id];1518assert(form, "'new_id' must be a defined form name");1519// Grab the InstructForm for the new instruction1520new_inst = form->is_instruction();1521assert(new_inst, "'new_id' must be an instruction name");1522if (node->is_ideal_if() && new_inst->is_ideal_if()) {1523fprintf(fp, " ((MachIfNode*)n%d)->_prob = _prob;\n", cnt);1524fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n", cnt);1525}15261527if (node->is_ideal_fastlock() && new_inst->is_ideal_fastlock()) {1528fprintf(fp, " ((MachFastLockNode*)n%d)->_counters = _counters;\n", cnt);1529fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n", cnt);1530fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n", cnt);1531}15321533// Fill in the bottom_type where requested1534if (node->captures_bottom_type(_globalNames) &&1535new_inst->captures_bottom_type(_globalNames)) {1536fprintf(fp, " ((MachTypeNode*)n%d)->_bottom_type = bottom_type();\n", cnt);1537}15381539const char *resultOper = new_inst->reduce_result();1540fprintf(fp," n%d->set_opnd_array(0, state->MachOperGenerator(%s));\n",1541cnt, machOperEnum(resultOper));15421543// get the formal operand NameList1544NameList *formal_lst = &new_inst->_parameters;1545formal_lst->reset();15461547// Handle any memory operand1548int memory_operand = new_inst->memory_operand(_globalNames);1549if( memory_operand != InstructForm::NO_MEMORY_OPERAND ) {1550int node_mem_op = node->memory_operand(_globalNames);1551assert( node_mem_op != InstructForm::NO_MEMORY_OPERAND,1552"expand rule member needs memory but top-level inst doesn't have any" );1553if (has_memory_edge) {1554// Copy memory edge1555fprintf(fp," if (mem != (Node*)1) {\n");1556fprintf(fp," n%d->add_req(_in[1]);\t// Add memory edge\n", cnt);1557fprintf(fp," }\n");1558}1559}15601561// Iterate over the new instruction's operands1562int prev_pos = -1;1563for( expand_instr->reset(); (opid = expand_instr->iter()) != NULL; ) {1564// Use 'parameter' at current position in list of new instruction's formals1565// instead of 'opid' when looking up info internal to new_inst1566const char *parameter = formal_lst->iter();1567if (!parameter) {1568globalAD->syntax_err(node->_linenum, "Operand %s of expand instruction %s has"1569" no equivalent in new instruction %s.",1570opid, node->_ident, new_inst->_ident);1571assert(0, "Wrong expand");1572}15731574// Check for an operand which is created in the expand rule1575if ((exp_pos = node->_exprule->_newopers.index(opid)) != -1) {1576new_pos = new_inst->operand_position(parameter,Component::USE);1577exp_pos += node->num_opnds();1578// If there is no use of the created operand, just skip it1579if (new_pos != NameList::Not_in_list) {1580//Copy the operand from the original made above1581fprintf(fp," n%d->set_opnd_array(%d, op%d->clone()); // %s\n",1582cnt, new_pos, exp_pos-node->num_opnds(), opid);1583// Check for who defines this operand & add edge if needed1584fprintf(fp," if(tmp%d != NULL)\n", exp_pos);1585fprintf(fp," n%d->add_req(tmp%d);\n", cnt, exp_pos);1586}1587}1588else {1589// Use operand name to get an index into instruction component list1590// ins = (InstructForm *) _globalNames[new_id];1591exp_pos = node->operand_position_format(opid);1592assert(exp_pos != -1, "Bad expand rule");1593if (prev_pos > exp_pos && expand_instruction->_matrule != NULL) {1594// For the add_req calls below to work correctly they need1595// to added in the same order that a match would add them.1596// This means that they would need to be in the order of1597// the components list instead of the formal parameters.1598// This is a sort of hidden invariant that previously1599// wasn't checked and could lead to incorrectly1600// constructed nodes.1601syntax_err(node->_linenum, "For expand in %s to work, parameter declaration order in %s must follow matchrule\n",1602node->_ident, new_inst->_ident);1603}1604prev_pos = exp_pos;16051606new_pos = new_inst->operand_position(parameter,Component::USE);1607if (new_pos != -1) {1608// Copy the operand from the ExpandNode to the new node1609fprintf(fp," n%d->set_opnd_array(%d, opnd_array(%d)->clone()); // %s\n",1610cnt, new_pos, exp_pos, opid);1611// For each operand add appropriate input edges by looking at tmp's1612fprintf(fp," if(tmp%d == this) {\n", exp_pos);1613// Grab corresponding edges from ExpandNode and insert them here1614fprintf(fp," for(unsigned i = 0; i < num%d; i++) {\n", exp_pos);1615fprintf(fp," n%d->add_req(_in[i + idx%d]);\n", cnt, exp_pos);1616fprintf(fp," }\n");1617fprintf(fp," }\n");1618// This value is generated by one of the new instructions1619fprintf(fp," else n%d->add_req(tmp%d);\n", cnt, exp_pos);1620}1621}16221623// Update the DAG tmp's for values defined by this instruction1624int new_def_pos = new_inst->operand_position(parameter,Component::DEF);1625Effect *eform = (Effect *)new_inst->_effects[parameter];1626// If this operand is a definition in either an effects rule1627// or a match rule1628if((eform) && (is_def(eform->_use_def))) {1629// Update the temp associated with this operand1630fprintf(fp," tmp%d = n%d;\n", exp_pos, cnt);1631}1632else if( new_def_pos != -1 ) {1633// Instruction defines a value but user did not declare it1634// in the 'effect' clause1635fprintf(fp," tmp%d = n%d;\n", exp_pos, cnt);1636}1637} // done iterating over a new instruction's operands16381639// Fix number of operands, as we do not generate redundant ones.1640// The matcher generates some redundant operands, which are removed1641// in the expand function (of the node we generate here). We don't1642// generate the redundant operands here, so set the correct _num_opnds.1643if (expand_instruction->num_opnds() != expand_instruction->num_unique_opnds()) {1644fprintf(fp, " n%d->_num_opnds = %d; // Only unique opnds generated.\n",1645cnt, expand_instruction->num_unique_opnds());1646}16471648// Invoke Expand() for the newly created instruction.1649fprintf(fp," result = n%d->Expand( state, proj_list, mem );\n", cnt);1650assert( !new_inst->expands(), "Do not have complete support for recursive expansion");1651} // done iterating over new instructions1652fprintf(fp,"\n");1653} // done generating expand rule16541655// Generate projections for instruction's additional DEFs and KILLs1656if( ! node->expands() && (node->needs_projections() || node->has_temps())) {1657// Get string representing the MachNode that projections point at1658const char *machNode = "this";1659// Generate the projections1660fprintf(fp," // Add projection edges for additional defs or kills\n");16611662// Examine each component to see if it is a DEF or KILL1663node->_components.reset();1664// Skip the first component, if already handled as (SET dst (...))1665Component *comp = NULL;1666// For kills, the choice of projection numbers is arbitrary1667int proj_no = 1;1668bool declared_def = false;1669bool declared_kill = false;16701671while ((comp = node->_components.iter()) != NULL) {1672// Lookup register class associated with operand type1673Form *form = (Form*)_globalNames[comp->_type];1674assert(form, "component type must be a defined form");1675OperandForm *op = form->is_operand();16761677if (comp->is(Component::TEMP) ||1678comp->is(Component::TEMP_DEF)) {1679fprintf(fp, " // TEMP %s\n", comp->_name);1680if (!declared_def) {1681// Define the variable "def" to hold new MachProjNodes1682fprintf(fp, " MachTempNode *def;\n");1683declared_def = true;1684}1685if (op && op->_interface && op->_interface->is_RegInterface()) {1686fprintf(fp," def = new MachTempNode(state->MachOperGenerator(%s));\n",1687machOperEnum(op->_ident));1688fprintf(fp," add_req(def);\n");1689// The operand for TEMP is already constructed during1690// this mach node construction, see buildMachNode().1691//1692// int idx = node->operand_position_format(comp->_name);1693// fprintf(fp," set_opnd_array(%d, state->MachOperGenerator(%s));\n",1694// idx, machOperEnum(op->_ident));1695} else {1696assert(false, "can't have temps which aren't registers");1697}1698} else if (comp->isa(Component::KILL)) {1699fprintf(fp, " // DEF/KILL %s\n", comp->_name);17001701if (!declared_kill) {1702// Define the variable "kill" to hold new MachProjNodes1703fprintf(fp, " MachProjNode *kill;\n");1704declared_kill = true;1705}17061707assert(op, "Support additional KILLS for base operands");1708const char *regmask = reg_mask(*op);1709const char *ideal_type = op->ideal_type(_globalNames, _register);17101711if (!op->is_bound_register()) {1712syntax_err(node->_linenum, "In %s only bound registers can be killed: %s %s\n",1713node->_ident, comp->_type, comp->_name);1714}17151716fprintf(fp," kill = ");1717fprintf(fp,"new MachProjNode( %s, %d, (%s), Op_%s );\n",1718machNode, proj_no++, regmask, ideal_type);1719fprintf(fp," proj_list.push(kill);\n");1720}1721}1722}17231724if( !node->expands() && node->_matrule != NULL ) {1725// Remove duplicated operands and inputs which use the same name.1726// Search through match operands for the same name usage.1727// The matcher generates these non-unique operands. If the node1728// was constructed by an expand rule, there are no unique operands.1729uint cur_num_opnds = node->num_opnds();1730if (cur_num_opnds > 1 && cur_num_opnds != node->num_unique_opnds()) {1731Component *comp = NULL;1732fprintf(fp, " // Remove duplicated operands and inputs which use the same name.\n");1733fprintf(fp, " if (num_opnds() == %d) {\n", cur_num_opnds);1734// Build mapping from num_edges to local variables1735fprintf(fp," unsigned num0 = 0;\n");1736for (i = 1; i < cur_num_opnds; i++) {1737fprintf(fp," unsigned num%d = opnd_array(%d)->num_edges();", i, i);1738fprintf(fp, " \t// %s\n", node->opnd_ident(i));1739}1740// Build a mapping from operand index to input edges1741fprintf(fp," unsigned idx0 = oper_input_base();\n");1742for (i = 0; i < cur_num_opnds; i++) {1743fprintf(fp," unsigned idx%d = idx%d + num%d;\n", i+1, i, i);1744}17451746uint new_num_opnds = 1;1747node->_components.reset();1748// Skip first unique operands.1749for (i = 1; i < cur_num_opnds; i++) {1750comp = node->_components.iter();1751if (i != node->unique_opnds_idx(i)) {1752break;1753}1754new_num_opnds++;1755}1756// Replace not unique operands with next unique operands.1757for ( ; i < cur_num_opnds; i++) {1758comp = node->_components.iter();1759uint j = node->unique_opnds_idx(i);1760// unique_opnds_idx(i) is unique if unique_opnds_idx(j) is not unique.1761if (j != node->unique_opnds_idx(j)) {1762fprintf(fp," set_opnd_array(%d, opnd_array(%d)->clone()); // %s\n",1763new_num_opnds, i, comp->_name);1764// Delete not unique edges here.1765fprintf(fp," for (unsigned i = 0; i < num%d; i++) {\n", i);1766fprintf(fp," set_req(i + idx%d, _in[i + idx%d]);\n", new_num_opnds, i);1767fprintf(fp," }\n");1768fprintf(fp," num%d = num%d;\n", new_num_opnds, i);1769fprintf(fp," idx%d = idx%d + num%d;\n", new_num_opnds+1, new_num_opnds, new_num_opnds);1770new_num_opnds++;1771}1772}1773// Delete the rest of edges.1774fprintf(fp," for (int i = idx%d - 1; i >= (int)idx%d; i--) {\n", cur_num_opnds, new_num_opnds);1775fprintf(fp," del_req(i);\n");1776fprintf(fp," }\n");1777fprintf(fp," _num_opnds = %d;\n", new_num_opnds);1778assert(new_num_opnds == node->num_unique_opnds(), "what?");1779fprintf(fp, " } else {\n");1780fprintf(fp, " assert(_num_opnds == %d, \"There should be either %d or %d operands.\");\n",1781new_num_opnds, new_num_opnds, cur_num_opnds);1782fprintf(fp, " }\n");1783}1784}17851786// If the node is a MachConstantNode, insert the MachConstantBaseNode edge.1787// NOTE: this edge must be the last input (see MachConstantNode::mach_constant_base_node_input).1788// There are nodes that don't use $constantablebase, but still require that it1789// is an input to the node. Example: divF_reg_immN, Repl32B_imm on x86_64.1790if (node->is_mach_constant() || node->needs_constant_base()) {1791if (node->is_ideal_call() != Form::invalid_type &&1792node->is_ideal_call() != Form::JAVA_LEAF) {1793fprintf(fp, " // MachConstantBaseNode added in matcher.\n");1794_needs_deep_clone_jvms = true;1795} else {1796fprintf(fp, " add_req(C->mach_constant_base_node());\n");1797}1798}17991800fprintf(fp, "\n");1801if (node->expands()) {1802fprintf(fp, " return result;\n");1803} else {1804fprintf(fp, " return this;\n");1805}1806fprintf(fp, "}\n");1807fprintf(fp, "\n");1808}180918101811//------------------------------Emit Routines----------------------------------1812// Special classes and routines for defining node emit routines which output1813// target specific instruction object encodings.1814// Define the ___Node::emit() routine1815//1816// (1) void ___Node::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {1817// (2) // ... encoding defined by user1818// (3)1819// (4) }1820//18211822class DefineEmitState {1823private:1824enum reloc_format { RELOC_NONE = -1,1825RELOC_IMMEDIATE = 0,1826RELOC_DISP = 1,1827RELOC_CALL_DISP = 2 };1828enum literal_status{ LITERAL_NOT_SEEN = 0,1829LITERAL_SEEN = 1,1830LITERAL_ACCESSED = 2,1831LITERAL_OUTPUT = 3 };1832// Temporaries that describe current operand1833bool _cleared;1834OpClassForm *_opclass;1835OperandForm *_operand;1836int _operand_idx;1837const char *_local_name;1838const char *_operand_name;1839bool _doing_disp;1840bool _doing_constant;1841Form::DataType _constant_type;1842DefineEmitState::literal_status _constant_status;1843DefineEmitState::literal_status _reg_status;1844bool _doing_emit8;1845bool _doing_emit_d32;1846bool _doing_emit_d16;1847bool _doing_emit_hi;1848bool _doing_emit_lo;1849bool _may_reloc;1850reloc_format _reloc_form;1851const char * _reloc_type;1852bool _processing_noninput;18531854NameList _strings_to_emit;18551856// Stable state, set by constructor1857ArchDesc &_AD;1858FILE *_fp;1859EncClass &_encoding;1860InsEncode &_ins_encode;1861InstructForm &_inst;18621863public:1864DefineEmitState(FILE *fp, ArchDesc &AD, EncClass &encoding,1865InsEncode &ins_encode, InstructForm &inst)1866: _AD(AD), _fp(fp), _encoding(encoding), _ins_encode(ins_encode), _inst(inst) {1867clear();1868}18691870void clear() {1871_cleared = true;1872_opclass = NULL;1873_operand = NULL;1874_operand_idx = 0;1875_local_name = "";1876_operand_name = "";1877_doing_disp = false;1878_doing_constant= false;1879_constant_type = Form::none;1880_constant_status = LITERAL_NOT_SEEN;1881_reg_status = LITERAL_NOT_SEEN;1882_doing_emit8 = false;1883_doing_emit_d32= false;1884_doing_emit_d16= false;1885_doing_emit_hi = false;1886_doing_emit_lo = false;1887_may_reloc = false;1888_reloc_form = RELOC_NONE;1889_reloc_type = AdlcVMDeps::none_reloc_type();1890_strings_to_emit.clear();1891}18921893// Track necessary state when identifying a replacement variable1894// @arg rep_var: The formal parameter of the encoding.1895void update_state(const char *rep_var) {1896// A replacement variable or one of its subfields1897// Obtain replacement variable from list1898if ( (*rep_var) != '$' ) {1899// A replacement variable, '$' prefix1900// check_rep_var( rep_var );1901if ( Opcode::as_opcode_type(rep_var) != Opcode::NOT_AN_OPCODE ) {1902// No state needed.1903assert( _opclass == NULL,1904"'primary', 'secondary' and 'tertiary' don't follow operand.");1905}1906else if ((strcmp(rep_var, "constanttablebase") == 0) ||1907(strcmp(rep_var, "constantoffset") == 0) ||1908(strcmp(rep_var, "constantaddress") == 0)) {1909if (!(_inst.is_mach_constant() || _inst.needs_constant_base())) {1910_AD.syntax_err(_encoding._linenum,1911"Replacement variable %s not allowed in instruct %s (only in MachConstantNode or MachCall).\n",1912rep_var, _encoding._name);1913}1914}1915else {1916// Lookup its position in (formal) parameter list of encoding1917int param_no = _encoding.rep_var_index(rep_var);1918if ( param_no == -1 ) {1919_AD.syntax_err( _encoding._linenum,1920"Replacement variable %s not found in enc_class %s.\n",1921rep_var, _encoding._name);1922}19231924// Lookup the corresponding ins_encode parameter1925// This is the argument (actual parameter) to the encoding.1926const char *inst_rep_var = _ins_encode.rep_var_name(_inst, param_no);1927if (inst_rep_var == NULL) {1928_AD.syntax_err( _ins_encode._linenum,1929"Parameter %s not passed to enc_class %s from instruct %s.\n",1930rep_var, _encoding._name, _inst._ident);1931assert(false, "inst_rep_var == NULL, cannot continue.");1932}19331934// Check if instruction's actual parameter is a local name in the instruction1935const Form *local = _inst._localNames[inst_rep_var];1936OpClassForm *opc = (local != NULL) ? local->is_opclass() : NULL;1937// Note: assert removed to allow constant and symbolic parameters1938// assert( opc, "replacement variable was not found in local names");1939// Lookup the index position iff the replacement variable is a localName1940int idx = (opc != NULL) ? _inst.operand_position_format(inst_rep_var) : -1;19411942if ( idx != -1 ) {1943// This is a local in the instruction1944// Update local state info.1945_opclass = opc;1946_operand_idx = idx;1947_local_name = rep_var;1948_operand_name = inst_rep_var;19491950// !!!!!1951// Do not support consecutive operands.1952assert( _operand == NULL, "Unimplemented()");1953_operand = opc->is_operand();1954}1955else if( ADLParser::is_literal_constant(inst_rep_var) ) {1956// Instruction provided a constant expression1957// Check later that encoding specifies $$$constant to resolve as constant1958_constant_status = LITERAL_SEEN;1959}1960else if( Opcode::as_opcode_type(inst_rep_var) != Opcode::NOT_AN_OPCODE ) {1961// Instruction provided an opcode: "primary", "secondary", "tertiary"1962// Check later that encoding specifies $$$constant to resolve as constant1963_constant_status = LITERAL_SEEN;1964}1965else if((_AD.get_registers() != NULL ) && (_AD.get_registers()->getRegDef(inst_rep_var) != NULL)) {1966// Instruction provided a literal register name for this parameter1967// Check that encoding specifies $$$reg to resolve.as register.1968_reg_status = LITERAL_SEEN;1969}1970else {1971// Check for unimplemented functionality before hard failure1972assert(opc != NULL && strcmp(opc->_ident, "label") == 0, "Unimplemented Label");1973assert(false, "ShouldNotReachHere()");1974}1975} // done checking which operand this is.1976} else {1977//1978// A subfield variable, '$$' prefix1979// Check for fields that may require relocation information.1980// Then check that literal register parameters are accessed with 'reg' or 'constant'1981//1982if ( strcmp(rep_var,"$disp") == 0 ) {1983_doing_disp = true;1984assert( _opclass, "Must use operand or operand class before '$disp'");1985if( _operand == NULL ) {1986// Only have an operand class, generate run-time check for relocation1987_may_reloc = true;1988_reloc_form = RELOC_DISP;1989_reloc_type = AdlcVMDeps::oop_reloc_type();1990} else {1991// Do precise check on operand: is it a ConP or not1992//1993// Check interface for value of displacement1994assert( ( _operand->_interface != NULL ),1995"$disp can only follow memory interface operand");1996MemInterface *mem_interface= _operand->_interface->is_MemInterface();1997assert( mem_interface != NULL,1998"$disp can only follow memory interface operand");1999const char *disp = mem_interface->_disp;20002001if( disp != NULL && (*disp == '$') ) {2002// MemInterface::disp contains a replacement variable,2003// Check if this matches a ConP2004//2005// Lookup replacement variable, in operand's component list2006const char *rep_var_name = disp + 1; // Skip '$'2007const Component *comp = _operand->_components.search(rep_var_name);2008assert( comp != NULL,"Replacement variable not found in components");2009const char *type = comp->_type;2010// Lookup operand form for replacement variable's type2011const Form *form = _AD.globalNames()[type];2012assert( form != NULL, "Replacement variable's type not found");2013OperandForm *op = form->is_operand();2014assert( op, "Attempting to emit a non-register or non-constant");2015// Check if this is a constant2016if (op->_matrule && op->_matrule->is_base_constant(_AD.globalNames())) {2017// Check which constant this name maps to: _c0, _c1, ..., _cn2018// const int idx = _operand.constant_position(_AD.globalNames(), comp);2019// assert( idx != -1, "Constant component not found in operand");2020Form::DataType dtype = op->is_base_constant(_AD.globalNames());2021if ( dtype == Form::idealP ) {2022_may_reloc = true;2023// No longer true that idealP is always an oop2024_reloc_form = RELOC_DISP;2025_reloc_type = AdlcVMDeps::oop_reloc_type();2026}2027}20282029else if( _operand->is_user_name_for_sReg() != Form::none ) {2030// The only non-constant allowed access to disp is an operand sRegX in a stackSlotX2031assert( op->ideal_to_sReg_type(type) != Form::none, "StackSlots access displacements using 'sRegs'");2032_may_reloc = false;2033} else {2034assert( false, "fatal(); Only stackSlots can access a non-constant using 'disp'");2035}2036}2037} // finished with precise check of operand for relocation.2038} // finished with subfield variable2039else if ( strcmp(rep_var,"$constant") == 0 ) {2040_doing_constant = true;2041if ( _constant_status == LITERAL_NOT_SEEN ) {2042// Check operand for type of constant2043assert( _operand, "Must use operand before '$$constant'");2044Form::DataType dtype = _operand->is_base_constant(_AD.globalNames());2045_constant_type = dtype;2046if ( dtype == Form::idealP ) {2047_may_reloc = true;2048// No longer true that idealP is always an oop2049// // _must_reloc = true;2050_reloc_form = RELOC_IMMEDIATE;2051_reloc_type = AdlcVMDeps::oop_reloc_type();2052} else {2053// No relocation information needed2054}2055} else {2056// User-provided literals may not require relocation information !!!!!2057assert( _constant_status == LITERAL_SEEN, "Must know we are processing a user-provided literal");2058}2059}2060else if ( strcmp(rep_var,"$label") == 0 ) {2061// Calls containing labels require relocation2062if ( _inst.is_ideal_call() ) {2063_may_reloc = true;2064// !!!!! !!!!!2065_reloc_type = AdlcVMDeps::none_reloc_type();2066}2067}20682069// literal register parameter must be accessed as a 'reg' field.2070if ( _reg_status != LITERAL_NOT_SEEN ) {2071assert( _reg_status == LITERAL_SEEN, "Must have seen register literal before now");2072if (strcmp(rep_var,"$reg") == 0 || reg_conversion(rep_var) != NULL) {2073_reg_status = LITERAL_ACCESSED;2074} else {2075_AD.syntax_err(_encoding._linenum,2076"Invalid access to literal register parameter '%s' in %s.\n",2077rep_var, _encoding._name);2078assert( false, "invalid access to literal register parameter");2079}2080}2081// literal constant parameters must be accessed as a 'constant' field2082if (_constant_status != LITERAL_NOT_SEEN) {2083assert(_constant_status == LITERAL_SEEN, "Must have seen constant literal before now");2084if (strcmp(rep_var,"$constant") == 0) {2085_constant_status = LITERAL_ACCESSED;2086} else {2087_AD.syntax_err(_encoding._linenum,2088"Invalid access to literal constant parameter '%s' in %s.\n",2089rep_var, _encoding._name);2090}2091}2092} // end replacement and/or subfield20932094}20952096void add_rep_var(const char *rep_var) {2097// Handle subfield and replacement variables.2098if ( ( *rep_var == '$' ) && ( *(rep_var+1) == '$' ) ) {2099// Check for emit prefix, '$$emit32'2100assert( _cleared, "Can not nest $$$emit32");2101if ( strcmp(rep_var,"$$emit32") == 0 ) {2102_doing_emit_d32 = true;2103}2104else if ( strcmp(rep_var,"$$emit16") == 0 ) {2105_doing_emit_d16 = true;2106}2107else if ( strcmp(rep_var,"$$emit_hi") == 0 ) {2108_doing_emit_hi = true;2109}2110else if ( strcmp(rep_var,"$$emit_lo") == 0 ) {2111_doing_emit_lo = true;2112}2113else if ( strcmp(rep_var,"$$emit8") == 0 ) {2114_doing_emit8 = true;2115}2116else {2117_AD.syntax_err(_encoding._linenum, "Unsupported $$operation '%s'\n",rep_var);2118assert( false, "fatal();");2119}2120}2121else {2122// Update state for replacement variables2123update_state( rep_var );2124_strings_to_emit.addName(rep_var);2125}2126_cleared = false;2127}21282129void emit_replacement() {2130// A replacement variable or one of its subfields2131// Obtain replacement variable from list2132// const char *ec_rep_var = encoding->_rep_vars.iter();2133const char *rep_var;2134_strings_to_emit.reset();2135while ( (rep_var = _strings_to_emit.iter()) != NULL ) {21362137if ( (*rep_var) == '$' ) {2138// A subfield variable, '$$' prefix2139emit_field( rep_var );2140} else {2141if (_strings_to_emit.peek() != NULL &&2142strcmp(_strings_to_emit.peek(), "$Address") == 0) {2143fprintf(_fp, "Address::make_raw(");21442145emit_rep_var( rep_var );2146fprintf(_fp,"->base(ra_,this,idx%d), ", _operand_idx);21472148_reg_status = LITERAL_ACCESSED;2149emit_rep_var( rep_var );2150fprintf(_fp,"->index(ra_,this,idx%d), ", _operand_idx);21512152_reg_status = LITERAL_ACCESSED;2153emit_rep_var( rep_var );2154fprintf(_fp,"->scale(), ");21552156_reg_status = LITERAL_ACCESSED;2157emit_rep_var( rep_var );2158Form::DataType stack_type = _operand ? _operand->is_user_name_for_sReg() : Form::none;2159if( _operand && _operand_idx==0 && stack_type != Form::none ) {2160fprintf(_fp,"->disp(ra_,this,0), ");2161} else {2162fprintf(_fp,"->disp(ra_,this,idx%d), ", _operand_idx);2163}21642165_reg_status = LITERAL_ACCESSED;2166emit_rep_var( rep_var );2167fprintf(_fp,"->disp_reloc())");21682169// skip trailing $Address2170_strings_to_emit.iter();2171} else {2172// A replacement variable, '$' prefix2173const char* next = _strings_to_emit.peek();2174const char* next2 = _strings_to_emit.peek(2);2175if (next != NULL && next2 != NULL && strcmp(next2, "$Register") == 0 &&2176(strcmp(next, "$base") == 0 || strcmp(next, "$index") == 0)) {2177// handle $rev_var$$base$$Register and $rev_var$$index$$Register by2178// producing as_Register(opnd_array(#)->base(ra_,this,idx1)).2179fprintf(_fp, "as_Register(");2180// emit the operand reference2181emit_rep_var( rep_var );2182rep_var = _strings_to_emit.iter();2183assert(strcmp(rep_var, "$base") == 0 || strcmp(rep_var, "$index") == 0, "bad pattern");2184// handle base or index2185emit_field(rep_var);2186rep_var = _strings_to_emit.iter();2187assert(strcmp(rep_var, "$Register") == 0, "bad pattern");2188// close up the parens2189fprintf(_fp, ")");2190} else {2191emit_rep_var( rep_var );2192}2193}2194} // end replacement and/or subfield2195}2196}21972198void emit_reloc_type(const char* type) {2199fprintf(_fp, "%s", type)2200;2201}220222032204void emit() {2205//2206// "emit_d32_reloc(" or "emit_hi_reloc" or "emit_lo_reloc"2207//2208// Emit the function name when generating an emit function2209if ( _doing_emit_d32 || _doing_emit_hi || _doing_emit_lo ) {2210const char *d32_hi_lo = _doing_emit_d32 ? "d32" : (_doing_emit_hi ? "hi" : "lo");2211// In general, relocatable isn't known at compiler compile time.2212// Check results of prior scan2213if ( ! _may_reloc ) {2214// Definitely don't need relocation information2215fprintf( _fp, "emit_%s(cbuf, ", d32_hi_lo );2216emit_replacement(); fprintf(_fp, ")");2217}2218else {2219// Emit RUNTIME CHECK to see if value needs relocation info2220// If emitting a relocatable address, use 'emit_d32_reloc'2221const char *disp_constant = _doing_disp ? "disp" : _doing_constant ? "constant" : "INVALID";2222assert( (_doing_disp || _doing_constant)2223&& !(_doing_disp && _doing_constant),2224"Must be emitting either a displacement or a constant");2225fprintf(_fp,"\n");2226fprintf(_fp,"if ( opnd_array(%d)->%s_reloc() != relocInfo::none ) {\n",2227_operand_idx, disp_constant);2228fprintf(_fp," ");2229fprintf(_fp,"emit_%s_reloc(cbuf, ", d32_hi_lo );2230emit_replacement(); fprintf(_fp,", ");2231fprintf(_fp,"opnd_array(%d)->%s_reloc(), ",2232_operand_idx, disp_constant);2233fprintf(_fp, "%d", _reloc_form);fprintf(_fp, ");");2234fprintf(_fp,"\n");2235fprintf(_fp,"} else {\n");2236fprintf(_fp," emit_%s(cbuf, ", d32_hi_lo);2237emit_replacement(); fprintf(_fp, ");\n"); fprintf(_fp,"}");2238}2239}2240else if ( _doing_emit_d16 ) {2241// Relocation of 16-bit values is not supported2242fprintf(_fp,"emit_d16(cbuf, ");2243emit_replacement(); fprintf(_fp, ")");2244// No relocation done for 16-bit values2245}2246else if ( _doing_emit8 ) {2247// Relocation of 8-bit values is not supported2248fprintf(_fp,"emit_d8(cbuf, ");2249emit_replacement(); fprintf(_fp, ")");2250// No relocation done for 8-bit values2251}2252else {2253// Not an emit# command, just output the replacement string.2254emit_replacement();2255}22562257// Get ready for next state collection.2258clear();2259}22602261private:22622263// recognizes names which represent MacroAssembler register types2264// and return the conversion function to build them from OptoReg2265const char* reg_conversion(const char* rep_var) {2266if (strcmp(rep_var,"$Register") == 0) return "as_Register";2267if (strcmp(rep_var,"$KRegister") == 0) return "as_KRegister";2268if (strcmp(rep_var,"$FloatRegister") == 0) return "as_FloatRegister";2269#if defined(IA32) || defined(AMD64)2270if (strcmp(rep_var,"$XMMRegister") == 0) return "as_XMMRegister";2271#endif2272if (strcmp(rep_var,"$CondRegister") == 0) return "as_ConditionRegister";2273#if defined(PPC64)2274if (strcmp(rep_var,"$VectorRegister") == 0) return "as_VectorRegister";2275if (strcmp(rep_var,"$VectorSRegister") == 0) return "as_VectorSRegister";2276#endif2277return NULL;2278}22792280void emit_field(const char *rep_var) {2281const char* reg_convert = reg_conversion(rep_var);22822283// A subfield variable, '$$subfield'2284if ( strcmp(rep_var, "$reg") == 0 || reg_convert != NULL) {2285// $reg form or the $Register MacroAssembler type conversions2286assert( _operand_idx != -1,2287"Must use this subfield after operand");2288if( _reg_status == LITERAL_NOT_SEEN ) {2289if (_processing_noninput) {2290const Form *local = _inst._localNames[_operand_name];2291OperandForm *oper = local->is_operand();2292const RegDef* first = oper->get_RegClass()->find_first_elem();2293if (reg_convert != NULL) {2294fprintf(_fp, "%s(%s_enc)", reg_convert, first->_regname);2295} else {2296fprintf(_fp, "%s_enc", first->_regname);2297}2298} else {2299fprintf(_fp,"->%s(ra_,this", reg_convert != NULL ? reg_convert : "reg");2300// Add parameter for index position, if not result operand2301if( _operand_idx != 0 ) fprintf(_fp,",idx%d", _operand_idx);2302fprintf(_fp,")");2303fprintf(_fp, "/* %s */", _operand_name);2304}2305} else {2306assert( _reg_status == LITERAL_OUTPUT, "should have output register literal in emit_rep_var");2307// Register literal has already been sent to output file, nothing more needed2308}2309}2310else if ( strcmp(rep_var,"$base") == 0 ) {2311assert( _operand_idx != -1,2312"Must use this subfield after operand");2313assert( ! _may_reloc, "UnImplemented()");2314fprintf(_fp,"->base(ra_,this,idx%d)", _operand_idx);2315}2316else if ( strcmp(rep_var,"$index") == 0 ) {2317assert( _operand_idx != -1,2318"Must use this subfield after operand");2319assert( ! _may_reloc, "UnImplemented()");2320fprintf(_fp,"->index(ra_,this,idx%d)", _operand_idx);2321}2322else if ( strcmp(rep_var,"$scale") == 0 ) {2323assert( ! _may_reloc, "UnImplemented()");2324fprintf(_fp,"->scale()");2325}2326else if ( strcmp(rep_var,"$cmpcode") == 0 ) {2327assert( ! _may_reloc, "UnImplemented()");2328fprintf(_fp,"->ccode()");2329}2330else if ( strcmp(rep_var,"$constant") == 0 ) {2331if( _constant_status == LITERAL_NOT_SEEN ) {2332if ( _constant_type == Form::idealD ) {2333fprintf(_fp,"->constantD()");2334} else if ( _constant_type == Form::idealF ) {2335fprintf(_fp,"->constantF()");2336} else if ( _constant_type == Form::idealL ) {2337fprintf(_fp,"->constantL()");2338} else {2339fprintf(_fp,"->constant()");2340}2341} else {2342assert( _constant_status == LITERAL_OUTPUT, "should have output constant literal in emit_rep_var");2343// Constant literal has already been sent to output file, nothing more needed2344}2345}2346else if ( strcmp(rep_var,"$disp") == 0 ) {2347Form::DataType stack_type = _operand ? _operand->is_user_name_for_sReg() : Form::none;2348if( _operand && _operand_idx==0 && stack_type != Form::none ) {2349fprintf(_fp,"->disp(ra_,this,0)");2350} else {2351fprintf(_fp,"->disp(ra_,this,idx%d)", _operand_idx);2352}2353}2354else if ( strcmp(rep_var,"$label") == 0 ) {2355fprintf(_fp,"->label()");2356}2357else if ( strcmp(rep_var,"$method") == 0 ) {2358fprintf(_fp,"->method()");2359}2360else {2361printf("emit_field: %s\n",rep_var);2362globalAD->syntax_err(_inst._linenum, "Unknown replacement variable %s in format statement of %s.",2363rep_var, _inst._ident);2364assert( false, "UnImplemented()");2365}2366}236723682369void emit_rep_var(const char *rep_var) {2370_processing_noninput = false;2371// A replacement variable, originally '$'2372if ( Opcode::as_opcode_type(rep_var) != Opcode::NOT_AN_OPCODE ) {2373if ((_inst._opcode == NULL) || !_inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(rep_var) )) {2374// Missing opcode2375_AD.syntax_err( _inst._linenum,2376"Missing $%s opcode definition in %s, used by encoding %s\n",2377rep_var, _inst._ident, _encoding._name);2378}2379}2380else if (strcmp(rep_var, "constanttablebase") == 0) {2381fprintf(_fp, "as_Register(ra_->get_encode(in(mach_constant_base_node_input())))");2382}2383else if (strcmp(rep_var, "constantoffset") == 0) {2384fprintf(_fp, "constant_offset()");2385}2386else if (strcmp(rep_var, "constantaddress") == 0) {2387fprintf(_fp, "InternalAddress(__ code()->consts()->start() + constant_offset())");2388}2389else {2390// Lookup its position in parameter list2391int param_no = _encoding.rep_var_index(rep_var);2392if ( param_no == -1 ) {2393_AD.syntax_err( _encoding._linenum,2394"Replacement variable %s not found in enc_class %s.\n",2395rep_var, _encoding._name);2396}2397// Lookup the corresponding ins_encode parameter2398const char *inst_rep_var = _ins_encode.rep_var_name(_inst, param_no);23992400// Check if instruction's actual parameter is a local name in the instruction2401const Form *local = _inst._localNames[inst_rep_var];2402OpClassForm *opc = (local != NULL) ? local->is_opclass() : NULL;2403// Note: assert removed to allow constant and symbolic parameters2404// assert( opc, "replacement variable was not found in local names");2405// Lookup the index position iff the replacement variable is a localName2406int idx = (opc != NULL) ? _inst.operand_position_format(inst_rep_var) : -1;2407if( idx != -1 ) {2408if (_inst.is_noninput_operand(idx)) {2409// This operand isn't a normal input so printing it is done2410// specially.2411_processing_noninput = true;2412} else {2413// Output the emit code for this operand2414fprintf(_fp,"opnd_array(%d)",idx);2415}2416assert( _operand == opc->is_operand(),2417"Previous emit $operand does not match current");2418}2419else if( ADLParser::is_literal_constant(inst_rep_var) ) {2420// else check if it is a constant expression2421// Removed following assert to allow primitive C types as arguments to encodings2422// assert( _constant_status == LITERAL_ACCESSED, "Must be processing a literal constant parameter");2423fprintf(_fp,"(%s)", inst_rep_var);2424_constant_status = LITERAL_OUTPUT;2425}2426else if( Opcode::as_opcode_type(inst_rep_var) != Opcode::NOT_AN_OPCODE ) {2427// else check if "primary", "secondary", "tertiary"2428assert( _constant_status == LITERAL_ACCESSED, "Must be processing a literal constant parameter");2429if ((_inst._opcode == NULL) || !_inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(inst_rep_var) )) {2430// Missing opcode2431_AD.syntax_err( _inst._linenum,2432"Missing $%s opcode definition in %s\n",2433rep_var, _inst._ident);24342435}2436_constant_status = LITERAL_OUTPUT;2437}2438else if((_AD.get_registers() != NULL ) && (_AD.get_registers()->getRegDef(inst_rep_var) != NULL)) {2439// Instruction provided a literal register name for this parameter2440// Check that encoding specifies $$$reg to resolve.as register.2441assert( _reg_status == LITERAL_ACCESSED, "Must be processing a literal register parameter");2442fprintf(_fp,"(%s_enc)", inst_rep_var);2443_reg_status = LITERAL_OUTPUT;2444}2445else {2446// Check for unimplemented functionality before hard failure2447assert(opc != NULL && strcmp(opc->_ident, "label") == 0, "Unimplemented Label");2448assert(false, "ShouldNotReachHere()");2449}2450// all done2451}2452}24532454}; // end class DefineEmitState245524562457void ArchDesc::defineSize(FILE *fp, InstructForm &inst) {24582459//(1)2460// Output instruction's emit prototype2461fprintf(fp,"uint %sNode::size(PhaseRegAlloc *ra_) const {\n",2462inst._ident);24632464fprintf(fp, " assert(VerifyOops || MachNode::size(ra_) <= %s, \"bad fixed size\");\n", inst._size);24652466//(2)2467// Print the size2468fprintf(fp, " return (VerifyOops ? MachNode::size(ra_) : %s);\n", inst._size);24692470// (3) and (4)2471fprintf(fp,"}\n\n");2472}24732474// Emit postalloc expand function.2475void ArchDesc::define_postalloc_expand(FILE *fp, InstructForm &inst) {2476InsEncode *ins_encode = inst._insencode;24772478// Output instruction's postalloc_expand prototype.2479fprintf(fp, "void %sNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {\n",2480inst._ident);24812482assert((_encode != NULL) && (ins_encode != NULL), "You must define an encode section.");24832484// Output each operand's offset into the array of registers.2485inst.index_temps(fp, _globalNames);24862487// Output variables "unsigned idx_<par_name>", Node *n_<par_name> and "MachOpnd *op_<par_name>"2488// for each parameter <par_name> specified in the encoding.2489ins_encode->reset();2490const char *ec_name = ins_encode->encode_class_iter();2491assert(ec_name != NULL, "Postalloc expand must specify an encoding.");24922493EncClass *encoding = _encode->encClass(ec_name);2494if (encoding == NULL) {2495fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);2496abort();2497}2498if (ins_encode->current_encoding_num_args() != encoding->num_args()) {2499globalAD->syntax_err(ins_encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",2500inst._ident, ins_encode->current_encoding_num_args(),2501ec_name, encoding->num_args());2502}25032504fprintf(fp, " // Access to ins and operands for postalloc expand.\n");2505const int buflen = 2000;2506char idxbuf[buflen]; char *ib = idxbuf; idxbuf[0] = '\0';2507char nbuf [buflen]; char *nb = nbuf; nbuf[0] = '\0';2508char opbuf [buflen]; char *ob = opbuf; opbuf[0] = '\0';25092510encoding->_parameter_type.reset();2511encoding->_parameter_name.reset();2512const char *type = encoding->_parameter_type.iter();2513const char *name = encoding->_parameter_name.iter();2514int param_no = 0;2515for (; (type != NULL) && (name != NULL);2516(type = encoding->_parameter_type.iter()), (name = encoding->_parameter_name.iter())) {2517const char* arg_name = ins_encode->rep_var_name(inst, param_no);2518int idx = inst.operand_position_format(arg_name);2519if (strcmp(arg_name, "constanttablebase") == 0) {2520ib += sprintf(ib, " unsigned idx_%-5s = mach_constant_base_node_input(); \t// %s, \t%s\n",2521name, type, arg_name);2522nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);2523// There is no operand for the constanttablebase.2524} else if (inst.is_noninput_operand(idx)) {2525globalAD->syntax_err(inst._linenum,2526"In %s: you can not pass the non-input %s to a postalloc expand encoding.\n",2527inst._ident, arg_name);2528} else {2529ib += sprintf(ib, " unsigned idx_%-5s = idx%d; \t// %s, \t%s\n",2530name, idx, type, arg_name);2531nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);2532ob += sprintf(ob, " %sOper *op_%s = (%sOper *)opnd_array(%d);\n", type, name, type, idx);2533}2534param_no++;2535}2536assert(ib < &idxbuf[buflen-1] && nb < &nbuf[buflen-1] && ob < &opbuf[buflen-1], "buffer overflow");25372538fprintf(fp, "%s", idxbuf);2539fprintf(fp, " Node *n_region = lookup(0);\n");2540fprintf(fp, "%s%s", nbuf, opbuf);2541fprintf(fp, " Compile *C = ra_->C;\n");25422543// Output this instruction's encodings.2544fprintf(fp, " {");2545const char *ec_code = NULL;2546const char *ec_rep_var = NULL;2547assert(encoding == _encode->encClass(ec_name), "");25482549DefineEmitState pending(fp, *this, *encoding, *ins_encode, inst);2550encoding->_code.reset();2551encoding->_rep_vars.reset();2552// Process list of user-defined strings,2553// and occurrences of replacement variables.2554// Replacement Vars are pushed into a list and then output.2555while ((ec_code = encoding->_code.iter()) != NULL) {2556if (! encoding->_code.is_signal(ec_code)) {2557// Emit pending code.2558pending.emit();2559pending.clear();2560// Emit this code section.2561fprintf(fp, "%s", ec_code);2562} else {2563// A replacement variable or one of its subfields.2564// Obtain replacement variable from list.2565ec_rep_var = encoding->_rep_vars.iter();2566pending.add_rep_var(ec_rep_var);2567}2568}2569// Emit pending code.2570pending.emit();2571pending.clear();2572fprintf(fp, " }\n");25732574fprintf(fp, "}\n\n");25752576ec_name = ins_encode->encode_class_iter();2577assert(ec_name == NULL, "Postalloc expand may only have one encoding.");2578}25792580// defineEmit -----------------------------------------------------------------2581void ArchDesc::defineEmit(FILE* fp, InstructForm& inst) {2582InsEncode* encode = inst._insencode;25832584// (1)2585// Output instruction's emit prototype2586fprintf(fp, "void %sNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {\n", inst._ident);25872588// If user did not define an encode section,2589// provide stub that does not generate any machine code.2590if( (_encode == NULL) || (encode == NULL) ) {2591fprintf(fp, " // User did not define an encode section.\n");2592fprintf(fp, "}\n");2593return;2594}25952596// Save current instruction's starting address (helps with relocation).2597fprintf(fp, " cbuf.set_insts_mark();\n");25982599// For MachConstantNodes which are ideal jump nodes, fill the jump table.2600if (inst.is_mach_constant() && inst.is_ideal_jump()) {2601fprintf(fp, " ra_->C->output()->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");2602}26032604// Output each operand's offset into the array of registers.2605inst.index_temps(fp, _globalNames);26062607// Output this instruction's encodings2608const char *ec_name;2609bool user_defined = false;2610encode->reset();2611while ((ec_name = encode->encode_class_iter()) != NULL) {2612fprintf(fp, " {\n");2613// Output user-defined encoding2614user_defined = true;26152616const char *ec_code = NULL;2617const char *ec_rep_var = NULL;2618EncClass *encoding = _encode->encClass(ec_name);2619if (encoding == NULL) {2620fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);2621abort();2622}26232624if (encode->current_encoding_num_args() != encoding->num_args()) {2625globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",2626inst._ident, encode->current_encoding_num_args(),2627ec_name, encoding->num_args());2628}26292630DefineEmitState pending(fp, *this, *encoding, *encode, inst);2631encoding->_code.reset();2632encoding->_rep_vars.reset();2633// Process list of user-defined strings,2634// and occurrences of replacement variables.2635// Replacement Vars are pushed into a list and then output2636while ((ec_code = encoding->_code.iter()) != NULL) {2637if (!encoding->_code.is_signal(ec_code)) {2638// Emit pending code2639pending.emit();2640pending.clear();2641// Emit this code section2642fprintf(fp, "%s", ec_code);2643} else {2644// A replacement variable or one of its subfields2645// Obtain replacement variable from list2646ec_rep_var = encoding->_rep_vars.iter();2647pending.add_rep_var(ec_rep_var);2648}2649}2650// Emit pending code2651pending.emit();2652pending.clear();2653fprintf(fp, " }\n");2654} // end while instruction's encodings26552656// Check if user stated which encoding to user2657if ( user_defined == false ) {2658fprintf(fp, " // User did not define which encode class to use.\n");2659}26602661// (3) and (4)2662fprintf(fp, "}\n\n");2663}26642665// defineEvalConstant ---------------------------------------------------------2666void ArchDesc::defineEvalConstant(FILE* fp, InstructForm& inst) {2667InsEncode* encode = inst._constant;26682669// (1)2670// Output instruction's emit prototype2671fprintf(fp, "void %sNode::eval_constant(Compile* C) {\n", inst._ident);26722673// For ideal jump nodes, add a jump-table entry.2674if (inst.is_ideal_jump()) {2675fprintf(fp, " _constant = C->output()->constant_table().add_jump_table(this);\n");2676}26772678// If user did not define an encode section,2679// provide stub that does not generate any machine code.2680if ((_encode == NULL) || (encode == NULL)) {2681fprintf(fp, " // User did not define an encode section.\n");2682fprintf(fp, "}\n");2683return;2684}26852686// Output this instruction's encodings2687const char *ec_name;2688bool user_defined = false;2689encode->reset();2690while ((ec_name = encode->encode_class_iter()) != NULL) {2691fprintf(fp, " {\n");2692// Output user-defined encoding2693user_defined = true;26942695const char *ec_code = NULL;2696const char *ec_rep_var = NULL;2697EncClass *encoding = _encode->encClass(ec_name);2698if (encoding == NULL) {2699fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);2700abort();2701}27022703if (encode->current_encoding_num_args() != encoding->num_args()) {2704globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",2705inst._ident, encode->current_encoding_num_args(),2706ec_name, encoding->num_args());2707}27082709DefineEmitState pending(fp, *this, *encoding, *encode, inst);2710encoding->_code.reset();2711encoding->_rep_vars.reset();2712// Process list of user-defined strings,2713// and occurrences of replacement variables.2714// Replacement Vars are pushed into a list and then output2715while ((ec_code = encoding->_code.iter()) != NULL) {2716if (!encoding->_code.is_signal(ec_code)) {2717// Emit pending code2718pending.emit();2719pending.clear();2720// Emit this code section2721fprintf(fp, "%s", ec_code);2722} else {2723// A replacement variable or one of its subfields2724// Obtain replacement variable from list2725ec_rep_var = encoding->_rep_vars.iter();2726pending.add_rep_var(ec_rep_var);2727}2728}2729// Emit pending code2730pending.emit();2731pending.clear();2732fprintf(fp, " }\n");2733} // end while instruction's encodings27342735// Check if user stated which encoding to user2736if (user_defined == false) {2737fprintf(fp, " // User did not define which encode class to use.\n");2738}27392740// (3) and (4)2741fprintf(fp, "}\n");2742}27432744// ---------------------------------------------------------------------------2745//--------Utilities to build MachOper and MachNode derived Classes------------2746// ---------------------------------------------------------------------------27472748//------------------------------Utilities to build Operand Classes------------2749static void defineIn_RegMask(FILE *fp, FormDict &globals, OperandForm &oper) {2750uint num_edges = oper.num_edges(globals);2751if( num_edges != 0 ) {2752// Method header2753fprintf(fp, "const RegMask *%sOper::in_RegMask(int index) const {\n",2754oper._ident);27552756// Assert that the index is in range.2757fprintf(fp, " assert(0 <= index && index < %d, \"index out of range\");\n",2758num_edges);27592760// Figure out if all RegMasks are the same.2761const char* first_reg_class = oper.in_reg_class(0, globals);2762bool all_same = true;2763assert(first_reg_class != NULL, "did not find register mask");27642765for (uint index = 1; all_same && index < num_edges; index++) {2766const char* some_reg_class = oper.in_reg_class(index, globals);2767assert(some_reg_class != NULL, "did not find register mask");2768if (strcmp(first_reg_class, some_reg_class) != 0) {2769all_same = false;2770}2771}27722773if (all_same) {2774// Return the sole RegMask.2775if (strcmp(first_reg_class, "stack_slots") == 0) {2776fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n");2777} else if (strcmp(first_reg_class, "dynamic") == 0) {2778fprintf(fp," return &RegMask::Empty;\n");2779} else {2780const char* first_reg_class_to_upper = toUpper(first_reg_class);2781fprintf(fp," return &%s_mask();\n", first_reg_class_to_upper);2782delete[] first_reg_class_to_upper;2783}2784} else {2785// Build a switch statement to return the desired mask.2786fprintf(fp," switch (index) {\n");27872788for (uint index = 0; index < num_edges; index++) {2789const char *reg_class = oper.in_reg_class(index, globals);2790assert(reg_class != NULL, "did not find register mask");2791if( !strcmp(reg_class, "stack_slots") ) {2792fprintf(fp, " case %d: return &(Compile::current()->FIRST_STACK_mask());\n", index);2793} else {2794const char* reg_class_to_upper = toUpper(reg_class);2795fprintf(fp, " case %d: return &%s_mask();\n", index, reg_class_to_upper);2796delete[] reg_class_to_upper;2797}2798}2799fprintf(fp," }\n");2800fprintf(fp," ShouldNotReachHere();\n");2801fprintf(fp," return NULL;\n");2802}28032804// Method close2805fprintf(fp, "}\n\n");2806}2807}28082809// generate code to create a clone for a class derived from MachOper2810//2811// (0) MachOper *MachOperXOper::clone() const {2812// (1) return new MachXOper( _ccode, _c0, _c1, ..., _cn);2813// (2) }2814//2815static void defineClone(FILE *fp, FormDict &globalNames, OperandForm &oper) {2816fprintf(fp,"MachOper *%sOper::clone() const {\n", oper._ident);2817// Check for constants that need to be copied over2818const int num_consts = oper.num_consts(globalNames);2819const bool is_ideal_bool = oper.is_ideal_bool();2820if( (num_consts > 0) ) {2821fprintf(fp," return new %sOper(", oper._ident);2822// generate parameters for constants2823int i = 0;2824fprintf(fp,"_c%d", i);2825for( i = 1; i < num_consts; ++i) {2826fprintf(fp,", _c%d", i);2827}2828// finish line (1)2829fprintf(fp,");\n");2830}2831else {2832assert( num_consts == 0, "Currently support zero or one constant per operand clone function");2833fprintf(fp," return new %sOper();\n", oper._ident);2834}2835// finish method2836fprintf(fp,"}\n");2837}28382839// Helper functions for bug 4796752, abstracted with minimal modification2840// from define_oper_interface()2841OperandForm *rep_var_to_operand(const char *encoding, OperandForm &oper, FormDict &globals) {2842OperandForm *op = NULL;2843// Check for replacement variable2844if( *encoding == '$' ) {2845// Replacement variable2846const char *rep_var = encoding + 1;2847// Lookup replacement variable, rep_var, in operand's component list2848const Component *comp = oper._components.search(rep_var);2849assert( comp != NULL, "Replacement variable not found in components");2850// Lookup operand form for replacement variable's type2851const char *type = comp->_type;2852Form *form = (Form*)globals[type];2853assert( form != NULL, "Replacement variable's type not found");2854op = form->is_operand();2855assert( op, "Attempting to emit a non-register or non-constant");2856}28572858return op;2859}28602861int rep_var_to_constant_index(const char *encoding, OperandForm &oper, FormDict &globals) {2862int idx = -1;2863// Check for replacement variable2864if( *encoding == '$' ) {2865// Replacement variable2866const char *rep_var = encoding + 1;2867// Lookup replacement variable, rep_var, in operand's component list2868const Component *comp = oper._components.search(rep_var);2869assert( comp != NULL, "Replacement variable not found in components");2870// Lookup operand form for replacement variable's type2871const char *type = comp->_type;2872Form *form = (Form*)globals[type];2873assert( form != NULL, "Replacement variable's type not found");2874OperandForm *op = form->is_operand();2875assert( op, "Attempting to emit a non-register or non-constant");2876// Check that this is a constant and find constant's index:2877if (op->_matrule && op->_matrule->is_base_constant(globals)) {2878idx = oper.constant_position(globals, comp);2879}2880}28812882return idx;2883}28842885bool is_regI(const char *encoding, OperandForm &oper, FormDict &globals ) {2886bool is_regI = false;28872888OperandForm *op = rep_var_to_operand(encoding, oper, globals);2889if( op != NULL ) {2890// Check that this is a register2891if ( (op->_matrule && op->_matrule->is_base_register(globals)) ) {2892// Register2893const char* ideal = op->ideal_type(globals);2894is_regI = (ideal && (op->ideal_to_Reg_type(ideal) == Form::idealI));2895}2896}28972898return is_regI;2899}29002901bool is_conP(const char *encoding, OperandForm &oper, FormDict &globals ) {2902bool is_conP = false;29032904OperandForm *op = rep_var_to_operand(encoding, oper, globals);2905if( op != NULL ) {2906// Check that this is a constant pointer2907if (op->_matrule && op->_matrule->is_base_constant(globals)) {2908// Constant2909Form::DataType dtype = op->is_base_constant(globals);2910is_conP = (dtype == Form::idealP);2911}2912}29132914return is_conP;2915}291629172918// Define a MachOper interface methods2919void ArchDesc::define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,2920const char *name, const char *encoding) {2921bool emit_position = false;2922int position = -1;29232924fprintf(fp," virtual int %s", name);2925// Generate access method for base, index, scale, disp, ...2926if( (strcmp(name,"base") == 0) || (strcmp(name,"index") == 0) ) {2927fprintf(fp,"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");2928emit_position = true;2929} else if ( (strcmp(name,"disp") == 0) ) {2930fprintf(fp,"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");2931} else {2932fprintf(fp, "() const {\n");2933}29342935// Check for hexadecimal value OR replacement variable2936if( *encoding == '$' ) {2937// Replacement variable2938const char *rep_var = encoding + 1;2939fprintf(fp," // Replacement variable: %s\n", encoding+1);2940// Lookup replacement variable, rep_var, in operand's component list2941const Component *comp = oper._components.search(rep_var);2942assert( comp != NULL, "Replacement variable not found in components");2943// Lookup operand form for replacement variable's type2944const char *type = comp->_type;2945Form *form = (Form*)globals[type];2946assert( form != NULL, "Replacement variable's type not found");2947OperandForm *op = form->is_operand();2948assert( op, "Attempting to emit a non-register or non-constant");2949// Check that this is a register or a constant and generate code:2950if ( (op->_matrule && op->_matrule->is_base_register(globals)) ) {2951// Register2952int idx_offset = oper.register_position( globals, rep_var);2953position = idx_offset;2954fprintf(fp," return (int)ra_->get_encode(node->in(idx");2955if ( idx_offset > 0 ) fprintf(fp, "+%d",idx_offset);2956fprintf(fp,"));\n");2957} else if ( op->ideal_to_sReg_type(op->_ident) != Form::none ) {2958// StackSlot for an sReg comes either from input node or from self, when idx==02959fprintf(fp," if( idx != 0 ) {\n");2960fprintf(fp," // Access stack offset (register number) for input operand\n");2961fprintf(fp," return ra_->reg2offset(ra_->get_reg_first(node->in(idx)));/* sReg */\n");2962fprintf(fp," }\n");2963fprintf(fp," // Access stack offset (register number) from myself\n");2964fprintf(fp," return ra_->reg2offset(ra_->get_reg_first(node));/* sReg */\n");2965} else if (op->_matrule && op->_matrule->is_base_constant(globals)) {2966// Constant2967// Check which constant this name maps to: _c0, _c1, ..., _cn2968const int idx = oper.constant_position(globals, comp);2969assert( idx != -1, "Constant component not found in operand");2970// Output code for this constant, type dependent.2971fprintf(fp," return (int)" );2972oper.access_constant(fp, globals, (uint)idx /* , const_type */);2973fprintf(fp,";\n");2974} else {2975assert( false, "Attempting to emit a non-register or non-constant");2976}2977}2978else if( *encoding == '0' && *(encoding+1) == 'x' ) {2979// Hex value2980fprintf(fp," return %s;\n", encoding);2981} else {2982globalAD->syntax_err(oper._linenum, "In operand %s: Do not support this encode constant: '%s' for %s.",2983oper._ident, encoding, name);2984assert( false, "Do not support octal or decimal encode constants");2985}2986fprintf(fp," }\n");29872988if( emit_position && (position != -1) && (oper.num_edges(globals) > 0) ) {2989fprintf(fp," virtual int %s_position() const { return %d; }\n", name, position);2990MemInterface *mem_interface = oper._interface->is_MemInterface();2991const char *base = mem_interface->_base;2992const char *disp = mem_interface->_disp;2993if( emit_position && (strcmp(name,"base") == 0)2994&& base != NULL && is_regI(base, oper, globals)2995&& disp != NULL && is_conP(disp, oper, globals) ) {2996// Found a memory access using a constant pointer for a displacement2997// and a base register containing an integer offset.2998// In this case the base and disp are reversed with respect to what2999// is expected by MachNode::get_base_and_disp() and MachNode::adr_type().3000// Provide a non-NULL return for disp_as_type() that will allow adr_type()3001// to correctly compute the access type for alias analysis.3002//3003// See BugId 4796752, operand indOffset32X in x86_32.ad3004int idx = rep_var_to_constant_index(disp, oper, globals);3005fprintf(fp," virtual const TypePtr *disp_as_type() const { return _c%d; }\n", idx);3006}3007}3008}30093010//3011// Construct the method to copy _idx, inputs and operands to new node.3012static void define_fill_new_machnode(bool used, FILE *fp_cpp) {3013fprintf(fp_cpp, "\n");3014fprintf(fp_cpp, "// Copy _idx, inputs and operands to new node\n");3015fprintf(fp_cpp, "void MachNode::fill_new_machnode(MachNode* node) const {\n");3016if( !used ) {3017fprintf(fp_cpp, " // This architecture does not have cisc or short branch instructions\n");3018fprintf(fp_cpp, " ShouldNotCallThis();\n");3019fprintf(fp_cpp, "}\n");3020} else {3021// New node must use same node index for access through allocator's tables3022fprintf(fp_cpp, " // New node must use same node index\n");3023fprintf(fp_cpp, " node->set_idx( _idx );\n");3024// Copy machine-independent inputs3025fprintf(fp_cpp, " // Copy machine-independent inputs\n");3026fprintf(fp_cpp, " for( uint j = 0; j < req(); j++ ) {\n");3027fprintf(fp_cpp, " node->add_req(in(j));\n");3028fprintf(fp_cpp, " }\n");3029// Copy machine operands to new MachNode3030fprintf(fp_cpp, " // Copy my operands, except for cisc position\n");3031fprintf(fp_cpp, " int nopnds = num_opnds();\n");3032fprintf(fp_cpp, " assert( node->num_opnds() == (uint)nopnds, \"Must have same number of operands\");\n");3033fprintf(fp_cpp, " MachOper **to = node->_opnds;\n");3034fprintf(fp_cpp, " for( int i = 0; i < nopnds; i++ ) {\n");3035fprintf(fp_cpp, " if( i != cisc_operand() ) \n");3036fprintf(fp_cpp, " to[i] = _opnds[i]->clone();\n");3037fprintf(fp_cpp, " }\n");3038fprintf(fp_cpp, "}\n");3039}3040fprintf(fp_cpp, "\n");3041}30423043//------------------------------defineClasses----------------------------------3044// Define members of MachNode and MachOper classes based on3045// operand and instruction lists3046void ArchDesc::defineClasses(FILE *fp) {30473048// Define the contents of an array containing the machine register names3049defineRegNames(fp, _register);3050// Define an array containing the machine register encoding values3051defineRegEncodes(fp, _register);3052// Generate an enumeration of user-defined register classes3053// and a list of register masks, one for each class.3054// Only define the RegMask value objects in the expand file.3055// Declare each as an extern const RegMask ...; in ad_<arch>.hpp3056declare_register_masks(_HPP_file._fp);3057// build_register_masks(fp);3058build_register_masks(_CPP_EXPAND_file._fp);3059// Define the pipe_classes3060build_pipe_classes(_CPP_PIPELINE_file._fp);30613062// Generate Machine Classes for each operand defined in AD file3063fprintf(fp,"\n");3064fprintf(fp,"\n");3065fprintf(fp,"//------------------Define classes derived from MachOper---------------------\n");3066// Iterate through all operands3067_operands.reset();3068OperandForm *oper;3069for( ; (oper = (OperandForm*)_operands.iter()) != NULL; ) {3070// Ensure this is a machine-world instruction3071if ( oper->ideal_only() ) continue;3072// !!!!!3073// The declaration of labelOper is in machine-independent file: machnode3074if ( strcmp(oper->_ident,"label") == 0 ) {3075defineIn_RegMask(_CPP_MISC_file._fp, _globalNames, *oper);30763077fprintf(fp,"MachOper *%sOper::clone() const {\n", oper->_ident);3078fprintf(fp," return new %sOper(_label, _block_num);\n", oper->_ident);3079fprintf(fp,"}\n");30803081fprintf(fp,"uint %sOper::opcode() const { return %s; }\n",3082oper->_ident, machOperEnum(oper->_ident));3083// // Currently all XXXOper::Hash() methods are identical (990820)3084// define_hash(fp, oper->_ident);3085// // Currently all XXXOper::Cmp() methods are identical (990820)3086// define_cmp(fp, oper->_ident);3087fprintf(fp,"\n");30883089continue;3090}30913092// The declaration of methodOper is in machine-independent file: machnode3093if ( strcmp(oper->_ident,"method") == 0 ) {3094defineIn_RegMask(_CPP_MISC_file._fp, _globalNames, *oper);30953096fprintf(fp,"MachOper *%sOper::clone() const {\n", oper->_ident);3097fprintf(fp," return new %sOper(_method);\n", oper->_ident);3098fprintf(fp,"}\n");30993100fprintf(fp,"uint %sOper::opcode() const { return %s; }\n",3101oper->_ident, machOperEnum(oper->_ident));3102// // Currently all XXXOper::Hash() methods are identical (990820)3103// define_hash(fp, oper->_ident);3104// // Currently all XXXOper::Cmp() methods are identical (990820)3105// define_cmp(fp, oper->_ident);3106fprintf(fp,"\n");31073108continue;3109}31103111defineIn_RegMask(fp, _globalNames, *oper);3112defineClone(_CPP_CLONE_file._fp, _globalNames, *oper);3113// // Currently all XXXOper::Hash() methods are identical (990820)3114// define_hash(fp, oper->_ident);3115// // Currently all XXXOper::Cmp() methods are identical (990820)3116// define_cmp(fp, oper->_ident);31173118// side-call to generate output that used to be in the header file:3119extern void gen_oper_format(FILE *fp, FormDict &globals, OperandForm &oper, bool for_c_file);3120gen_oper_format(_CPP_FORMAT_file._fp, _globalNames, *oper, true);31213122}312331243125// Generate Machine Classes for each instruction defined in AD file3126fprintf(fp,"//------------------Define members for classes derived from MachNode----------\n");3127// Output the definitions for out_RegMask() // & kill_RegMask()3128_instructions.reset();3129InstructForm *instr;3130MachNodeForm *machnode;3131for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3132// Ensure this is a machine-world instruction3133if ( instr->ideal_only() ) continue;31343135defineOut_RegMask(_CPP_MISC_file._fp, instr->_ident, reg_mask(*instr));3136}31373138bool used = false;3139// Output the definitions for expand rules & peephole rules3140_instructions.reset();3141for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3142// Ensure this is a machine-world instruction3143if ( instr->ideal_only() ) continue;3144// If there are multiple defs/kills, or an explicit expand rule, build rule3145if( instr->expands() || instr->needs_projections() ||3146instr->has_temps() ||3147instr->is_mach_constant() ||3148instr->needs_constant_base() ||3149(instr->_matrule != NULL &&3150instr->num_opnds() != instr->num_unique_opnds()) )3151defineExpand(_CPP_EXPAND_file._fp, instr);3152// If there is an explicit peephole rule, build it3153if ( instr->peepholes() )3154definePeephole(_CPP_PEEPHOLE_file._fp, instr);31553156// Output code to convert to the cisc version, if applicable3157used |= instr->define_cisc_version(*this, fp);31583159// Output code to convert to the short branch version, if applicable3160used |= instr->define_short_branch_methods(*this, fp);3161}31623163// Construct the method called by cisc_version() to copy inputs and operands.3164define_fill_new_machnode(used, fp);31653166// Output the definitions for labels3167_instructions.reset();3168while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {3169// Ensure this is a machine-world instruction3170if ( instr->ideal_only() ) continue;31713172// Access the fields for operand Label3173int label_position = instr->label_position();3174if( label_position != -1 ) {3175// Set the label3176fprintf(fp,"void %sNode::label_set( Label* label, uint block_num ) {\n", instr->_ident);3177fprintf(fp," labelOper* oper = (labelOper*)(opnd_array(%d));\n",3178label_position );3179fprintf(fp," oper->_label = label;\n");3180fprintf(fp," oper->_block_num = block_num;\n");3181fprintf(fp,"}\n");3182// Save the label3183fprintf(fp,"void %sNode::save_label( Label** label, uint* block_num ) {\n", instr->_ident);3184fprintf(fp," labelOper* oper = (labelOper*)(opnd_array(%d));\n",3185label_position );3186fprintf(fp," *label = oper->_label;\n");3187fprintf(fp," *block_num = oper->_block_num;\n");3188fprintf(fp,"}\n");3189}3190}31913192// Output the definitions for methods3193_instructions.reset();3194while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {3195// Ensure this is a machine-world instruction3196if ( instr->ideal_only() ) continue;31973198// Access the fields for operand Label3199int method_position = instr->method_position();3200if( method_position != -1 ) {3201// Access the method's address3202fprintf(fp,"void %sNode::method_set( intptr_t method ) {\n", instr->_ident);3203fprintf(fp," ((methodOper*)opnd_array(%d))->_method = method;\n",3204method_position );3205fprintf(fp,"}\n");3206fprintf(fp,"\n");3207}3208}32093210// Define this instruction's number of relocation entries, base is '0'3211_instructions.reset();3212while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {3213// Output the definition for number of relocation entries3214uint reloc_size = instr->reloc(_globalNames);3215if ( reloc_size != 0 ) {3216fprintf(fp,"int %sNode::reloc() const {\n", instr->_ident);3217fprintf(fp," return %d;\n", reloc_size);3218fprintf(fp,"}\n");3219fprintf(fp,"\n");3220}3221}3222fprintf(fp,"\n");32233224// Output the definitions for code generation3225//3226// address ___Node::emit(address ptr, PhaseRegAlloc *ra_) const {3227// // ... encoding defined by user3228// return ptr;3229// }3230//3231_instructions.reset();3232for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3233// Ensure this is a machine-world instruction3234if ( instr->ideal_only() ) continue;32353236if (instr->_insencode) {3237if (instr->postalloc_expands()) {3238// Don't write this to _CPP_EXPAND_file, as the code generated calls C-code3239// from code sections in ad file that is dumped to fp.3240define_postalloc_expand(fp, *instr);3241} else {3242defineEmit(fp, *instr);3243}3244}3245if (instr->is_mach_constant()) defineEvalConstant(fp, *instr);3246if (instr->_size) defineSize (fp, *instr);32473248// side-call to generate output that used to be in the header file:3249extern void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &oper, bool for_c_file);3250gen_inst_format(_CPP_FORMAT_file._fp, _globalNames, *instr, true);3251}32523253// Output the definitions for alias analysis3254_instructions.reset();3255for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3256// Ensure this is a machine-world instruction3257if ( instr->ideal_only() ) continue;32583259// Analyze machine instructions that either USE or DEF memory.3260int memory_operand = instr->memory_operand(_globalNames);32613262if ( memory_operand != InstructForm::NO_MEMORY_OPERAND ) {3263if( memory_operand == InstructForm::MANY_MEMORY_OPERANDS ) {3264fprintf(fp,"const TypePtr *%sNode::adr_type() const { return TypePtr::BOTTOM; }\n", instr->_ident);3265fprintf(fp,"const MachOper* %sNode::memory_operand() const { return (MachOper*)-1; }\n", instr->_ident);3266} else {3267fprintf(fp,"const MachOper* %sNode::memory_operand() const { return _opnds[%d]; }\n", instr->_ident, memory_operand);3268}3269}3270}32713272// Get the length of the longest identifier3273int max_ident_len = 0;3274_instructions.reset();32753276for ( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3277if (instr->_ins_pipe && _pipeline->_classlist.search(instr->_ins_pipe)) {3278int ident_len = (int)strlen(instr->_ident);3279if( max_ident_len < ident_len )3280max_ident_len = ident_len;3281}3282}32833284// Emit specifically for Node(s)3285fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline_class() { return %s; }\n",3286max_ident_len, "Node", _pipeline ? "(&pipeline_class_Zero_Instructions)" : "NULL");3287fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline() const { return %s; }\n",3288max_ident_len, "Node", _pipeline ? "(&pipeline_class_Zero_Instructions)" : "NULL");3289fprintf(_CPP_PIPELINE_file._fp, "\n");32903291fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline_class() { return %s; }\n",3292max_ident_len, "MachNode", _pipeline ? "(&pipeline_class_Unknown_Instructions)" : "NULL");3293fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline() const { return pipeline_class(); }\n",3294max_ident_len, "MachNode");3295fprintf(_CPP_PIPELINE_file._fp, "\n");32963297// Output the definitions for machine node specific pipeline data3298_machnodes.reset();32993300if (_pipeline != NULL) {3301for ( ; (machnode = (MachNodeForm*)_machnodes.iter()) != NULL; ) {3302fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %sNode::pipeline() const { return (&pipeline_class_%03d); }\n",3303machnode->_ident, ((class PipeClassForm *)_pipeline->_classdict[machnode->_machnode_pipe])->_num);3304}3305}33063307fprintf(_CPP_PIPELINE_file._fp, "\n");33083309// Output the definitions for instruction pipeline static data references3310_instructions.reset();33113312if (_pipeline != NULL) {3313for ( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3314if (instr->_ins_pipe && _pipeline->_classlist.search(instr->_ins_pipe)) {3315fprintf(_CPP_PIPELINE_file._fp, "\n");3316fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*sNode::pipeline_class() { return (&pipeline_class_%03d); }\n",3317max_ident_len, instr->_ident, ((class PipeClassForm *)_pipeline->_classdict[instr->_ins_pipe])->_num);3318fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*sNode::pipeline() const { return (&pipeline_class_%03d); }\n",3319max_ident_len, instr->_ident, ((class PipeClassForm *)_pipeline->_classdict[instr->_ins_pipe])->_num);3320}3321}3322}3323}332433253326// -------------------------------- maps ------------------------------------33273328// Information needed to generate the ReduceOp mapping for the DFA3329class OutputReduceOp : public OutputMap {3330public:3331OutputReduceOp(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3332: OutputMap(hpp, cpp, globals, AD, "reduceOp") {};33333334void declaration() { fprintf(_hpp, "extern const int reduceOp[];\n"); }3335void definition() { fprintf(_cpp, "const int reduceOp[] = {\n"); }3336void closing() { fprintf(_cpp, " 0 // no trailing comma\n");3337OutputMap::closing();3338}3339void map(OpClassForm &opc) {3340const char *reduce = opc._ident;3341if( reduce ) fprintf(_cpp, " %s_rule", reduce);3342else fprintf(_cpp, " 0");3343}3344void map(OperandForm &oper) {3345// Most operands without match rules, e.g. eFlagsReg, do not have a result operand3346const char *reduce = (oper._matrule ? oper.reduce_result() : NULL);3347// operand stackSlot does not have a match rule, but produces a stackSlot3348if( oper.is_user_name_for_sReg() != Form::none ) reduce = oper.reduce_result();3349if( reduce ) fprintf(_cpp, " %s_rule", reduce);3350else fprintf(_cpp, " 0");3351}3352void map(InstructForm &inst) {3353const char *reduce = (inst._matrule ? inst.reduce_result() : NULL);3354if( reduce ) fprintf(_cpp, " %s_rule", reduce);3355else fprintf(_cpp, " 0");3356}3357void map(char *reduce) {3358if( reduce ) fprintf(_cpp, " %s_rule", reduce);3359else fprintf(_cpp, " 0");3360}3361};33623363// Information needed to generate the LeftOp mapping for the DFA3364class OutputLeftOp : public OutputMap {3365public:3366OutputLeftOp(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3367: OutputMap(hpp, cpp, globals, AD, "leftOp") {};33683369void declaration() { fprintf(_hpp, "extern const int leftOp[];\n"); }3370void definition() { fprintf(_cpp, "const int leftOp[] = {\n"); }3371void closing() { fprintf(_cpp, " 0 // no trailing comma\n");3372OutputMap::closing();3373}3374void map(OpClassForm &opc) { fprintf(_cpp, " 0"); }3375void map(OperandForm &oper) {3376const char *reduce = oper.reduce_left(_globals);3377if( reduce ) fprintf(_cpp, " %s_rule", reduce);3378else fprintf(_cpp, " 0");3379}3380void map(char *name) {3381const char *reduce = _AD.reduceLeft(name);3382if( reduce ) fprintf(_cpp, " %s_rule", reduce);3383else fprintf(_cpp, " 0");3384}3385void map(InstructForm &inst) {3386const char *reduce = inst.reduce_left(_globals);3387if( reduce ) fprintf(_cpp, " %s_rule", reduce);3388else fprintf(_cpp, " 0");3389}3390};339133923393// Information needed to generate the RightOp mapping for the DFA3394class OutputRightOp : public OutputMap {3395public:3396OutputRightOp(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3397: OutputMap(hpp, cpp, globals, AD, "rightOp") {};33983399void declaration() { fprintf(_hpp, "extern const int rightOp[];\n"); }3400void definition() { fprintf(_cpp, "const int rightOp[] = {\n"); }3401void closing() { fprintf(_cpp, " 0 // no trailing comma\n");3402OutputMap::closing();3403}3404void map(OpClassForm &opc) { fprintf(_cpp, " 0"); }3405void map(OperandForm &oper) {3406const char *reduce = oper.reduce_right(_globals);3407if( reduce ) fprintf(_cpp, " %s_rule", reduce);3408else fprintf(_cpp, " 0");3409}3410void map(char *name) {3411const char *reduce = _AD.reduceRight(name);3412if( reduce ) fprintf(_cpp, " %s_rule", reduce);3413else fprintf(_cpp, " 0");3414}3415void map(InstructForm &inst) {3416const char *reduce = inst.reduce_right(_globals);3417if( reduce ) fprintf(_cpp, " %s_rule", reduce);3418else fprintf(_cpp, " 0");3419}3420};342134223423// Information needed to generate the Rule names for the DFA3424class OutputRuleName : public OutputMap {3425public:3426OutputRuleName(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3427: OutputMap(hpp, cpp, globals, AD, "ruleName") {};34283429void declaration() { fprintf(_hpp, "extern const char *ruleName[];\n"); }3430void definition() { fprintf(_cpp, "const char *ruleName[] = {\n"); }3431void closing() { fprintf(_cpp, " \"invalid rule name\" // no trailing comma\n");3432OutputMap::closing();3433}3434void map(OpClassForm &opc) { fprintf(_cpp, " \"%s\"", _AD.machOperEnum(opc._ident) ); }3435void map(OperandForm &oper) { fprintf(_cpp, " \"%s\"", _AD.machOperEnum(oper._ident) ); }3436void map(char *name) { fprintf(_cpp, " \"%s\"", name ? name : "0"); }3437void map(InstructForm &inst){ fprintf(_cpp, " \"%s\"", inst._ident ? inst._ident : "0"); }3438};343934403441// Information needed to generate the swallowed mapping for the DFA3442class OutputSwallowed : public OutputMap {3443public:3444OutputSwallowed(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3445: OutputMap(hpp, cpp, globals, AD, "swallowed") {};34463447void declaration() { fprintf(_hpp, "extern const bool swallowed[];\n"); }3448void definition() { fprintf(_cpp, "const bool swallowed[] = {\n"); }3449void closing() { fprintf(_cpp, " false // no trailing comma\n");3450OutputMap::closing();3451}3452void map(OperandForm &oper) { // Generate the entry for this opcode3453const char *swallowed = oper.swallowed(_globals) ? "true" : "false";3454fprintf(_cpp, " %s", swallowed);3455}3456void map(OpClassForm &opc) { fprintf(_cpp, " false"); }3457void map(char *name) { fprintf(_cpp, " false"); }3458void map(InstructForm &inst){ fprintf(_cpp, " false"); }3459};346034613462// Information needed to generate the decision array for instruction chain rule3463class OutputInstChainRule : public OutputMap {3464public:3465OutputInstChainRule(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3466: OutputMap(hpp, cpp, globals, AD, "instruction_chain_rule") {};34673468void declaration() { fprintf(_hpp, "extern const bool instruction_chain_rule[];\n"); }3469void definition() { fprintf(_cpp, "const bool instruction_chain_rule[] = {\n"); }3470void closing() { fprintf(_cpp, " false // no trailing comma\n");3471OutputMap::closing();3472}3473void map(OpClassForm &opc) { fprintf(_cpp, " false"); }3474void map(OperandForm &oper) { fprintf(_cpp, " false"); }3475void map(char *name) { fprintf(_cpp, " false"); }3476void map(InstructForm &inst) { // Check for simple chain rule3477const char *chain = inst.is_simple_chain_rule(_globals) ? "true" : "false";3478fprintf(_cpp, " %s", chain);3479}3480};348134823483//---------------------------build_map------------------------------------3484// Build mapping from enumeration for densely packed operands3485// TO result and child types.3486void ArchDesc::build_map(OutputMap &map) {3487FILE *fp_hpp = map.decl_file();3488FILE *fp_cpp = map.def_file();3489int idx = 0;3490OperandForm *op;3491OpClassForm *opc;3492InstructForm *inst;34933494// Construct this mapping3495map.declaration();3496fprintf(fp_cpp,"\n");3497map.definition();34983499// Output the mapping for operands3500map.record_position(OutputMap::BEGIN_OPERANDS, idx );3501_operands.reset();3502for(; (op = (OperandForm*)_operands.iter()) != NULL; ) {3503// Ensure this is a machine-world instruction3504if ( op->ideal_only() ) continue;35053506// Generate the entry for this opcode3507fprintf(fp_cpp, " /* %4d */", idx); map.map(*op); fprintf(fp_cpp, ",\n");3508++idx;3509};3510fprintf(fp_cpp, " // last operand\n");35113512// Place all user-defined operand classes into the mapping3513map.record_position(OutputMap::BEGIN_OPCLASSES, idx );3514_opclass.reset();3515for(; (opc = (OpClassForm*)_opclass.iter()) != NULL; ) {3516fprintf(fp_cpp, " /* %4d */", idx); map.map(*opc); fprintf(fp_cpp, ",\n");3517++idx;3518};3519fprintf(fp_cpp, " // last operand class\n");35203521// Place all internally defined operands into the mapping3522map.record_position(OutputMap::BEGIN_INTERNALS, idx );3523_internalOpNames.reset();3524char *name = NULL;3525for(; (name = (char *)_internalOpNames.iter()) != NULL; ) {3526fprintf(fp_cpp, " /* %4d */", idx); map.map(name); fprintf(fp_cpp, ",\n");3527++idx;3528};3529fprintf(fp_cpp, " // last internally defined operand\n");35303531// Place all user-defined instructions into the mapping3532if( map.do_instructions() ) {3533map.record_position(OutputMap::BEGIN_INSTRUCTIONS, idx );3534// Output all simple instruction chain rules first3535map.record_position(OutputMap::BEGIN_INST_CHAIN_RULES, idx );3536{3537_instructions.reset();3538for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3539// Ensure this is a machine-world instruction3540if ( inst->ideal_only() ) continue;3541if ( ! inst->is_simple_chain_rule(_globalNames) ) continue;3542if ( inst->rematerialize(_globalNames, get_registers()) ) continue;35433544fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3545++idx;3546};3547map.record_position(OutputMap::BEGIN_REMATERIALIZE, idx );3548_instructions.reset();3549for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3550// Ensure this is a machine-world instruction3551if ( inst->ideal_only() ) continue;3552if ( ! inst->is_simple_chain_rule(_globalNames) ) continue;3553if ( ! inst->rematerialize(_globalNames, get_registers()) ) continue;35543555fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3556++idx;3557};3558map.record_position(OutputMap::END_INST_CHAIN_RULES, idx );3559}3560// Output all instructions that are NOT simple chain rules3561{3562_instructions.reset();3563for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3564// Ensure this is a machine-world instruction3565if ( inst->ideal_only() ) continue;3566if ( inst->is_simple_chain_rule(_globalNames) ) continue;3567if ( ! inst->rematerialize(_globalNames, get_registers()) ) continue;35683569fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3570++idx;3571};3572map.record_position(OutputMap::END_REMATERIALIZE, idx );3573_instructions.reset();3574for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3575// Ensure this is a machine-world instruction3576if ( inst->ideal_only() ) continue;3577if ( inst->is_simple_chain_rule(_globalNames) ) continue;3578if ( inst->rematerialize(_globalNames, get_registers()) ) continue;35793580fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3581++idx;3582};3583}3584fprintf(fp_cpp, " // last instruction\n");3585map.record_position(OutputMap::END_INSTRUCTIONS, idx );3586}3587// Finish defining table3588map.closing();3589};359035913592// Helper function for buildReduceMaps3593char reg_save_policy(const char *calling_convention) {3594char callconv;35953596if (!strcmp(calling_convention, "NS")) callconv = 'N';3597else if (!strcmp(calling_convention, "SOE")) callconv = 'E';3598else if (!strcmp(calling_convention, "SOC")) callconv = 'C';3599else if (!strcmp(calling_convention, "AS")) callconv = 'A';3600else callconv = 'Z';36013602return callconv;3603}36043605void ArchDesc::generate_needs_deep_clone_jvms(FILE *fp_cpp) {3606fprintf(fp_cpp, "bool Compile::needs_deep_clone_jvms() { return %s; }\n\n",3607_needs_deep_clone_jvms ? "true" : "false");3608}36093610//---------------------------generate_assertion_checks-------------------3611void ArchDesc::generate_adlc_verification(FILE *fp_cpp) {3612fprintf(fp_cpp, "\n");36133614fprintf(fp_cpp, "#ifndef PRODUCT\n");3615fprintf(fp_cpp, "void Compile::adlc_verification() {\n");3616globalDefs().print_asserts(fp_cpp);3617fprintf(fp_cpp, "}\n");3618fprintf(fp_cpp, "#endif\n");3619fprintf(fp_cpp, "\n");3620}36213622//---------------------------addSourceBlocks-----------------------------3623void ArchDesc::addSourceBlocks(FILE *fp_cpp) {3624if (_source.count() > 0)3625_source.output(fp_cpp);36263627generate_adlc_verification(fp_cpp);3628}3629//---------------------------addHeaderBlocks-----------------------------3630void ArchDesc::addHeaderBlocks(FILE *fp_hpp) {3631if (_header.count() > 0)3632_header.output(fp_hpp);3633}3634//-------------------------addPreHeaderBlocks----------------------------3635void ArchDesc::addPreHeaderBlocks(FILE *fp_hpp) {3636// Output #defines from definition block3637globalDefs().print_defines(fp_hpp);36383639if (_pre_header.count() > 0)3640_pre_header.output(fp_hpp);3641}36423643//---------------------------buildReduceMaps-----------------------------3644// Build mapping from enumeration for densely packed operands3645// TO result and child types.3646void ArchDesc::buildReduceMaps(FILE *fp_hpp, FILE *fp_cpp) {3647RegDef *rdef;3648RegDef *next;36493650// The emit bodies currently require functions defined in the source block.36513652// Build external declarations for mappings3653fprintf(fp_hpp, "\n");3654fprintf(fp_hpp, "extern const char register_save_policy[];\n");3655fprintf(fp_hpp, "extern const char c_reg_save_policy[];\n");3656fprintf(fp_hpp, "extern const int register_save_type[];\n");3657fprintf(fp_hpp, "\n");36583659// Construct Save-Policy array3660fprintf(fp_cpp, "// Map from machine-independent register number to register_save_policy\n");3661fprintf(fp_cpp, "const char register_save_policy[] = {\n");3662_register->reset_RegDefs();3663for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {3664next = _register->iter_RegDefs();3665char policy = reg_save_policy(rdef->_callconv);3666const char *comma = (next != NULL) ? "," : " // no trailing comma";3667fprintf(fp_cpp, " '%c'%s // %s\n", policy, comma, rdef->_regname);3668}3669fprintf(fp_cpp, "};\n\n");36703671// Construct Native Save-Policy array3672fprintf(fp_cpp, "// Map from machine-independent register number to c_reg_save_policy\n");3673fprintf(fp_cpp, "const char c_reg_save_policy[] = {\n");3674_register->reset_RegDefs();3675for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {3676next = _register->iter_RegDefs();3677char policy = reg_save_policy(rdef->_c_conv);3678const char *comma = (next != NULL) ? "," : " // no trailing comma";3679fprintf(fp_cpp, " '%c'%s // %s\n", policy, comma, rdef->_regname);3680}3681fprintf(fp_cpp, "};\n\n");36823683// Construct Register Save Type array3684fprintf(fp_cpp, "// Map from machine-independent register number to register_save_type\n");3685fprintf(fp_cpp, "const int register_save_type[] = {\n");3686_register->reset_RegDefs();3687for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {3688next = _register->iter_RegDefs();3689const char *comma = (next != NULL) ? "," : " // no trailing comma";3690fprintf(fp_cpp, " %s%s\n", rdef->_idealtype, comma);3691}3692fprintf(fp_cpp, "};\n\n");36933694// Construct the table for reduceOp3695OutputReduceOp output_reduce_op(fp_hpp, fp_cpp, _globalNames, *this);3696build_map(output_reduce_op);3697// Construct the table for leftOp3698OutputLeftOp output_left_op(fp_hpp, fp_cpp, _globalNames, *this);3699build_map(output_left_op);3700// Construct the table for rightOp3701OutputRightOp output_right_op(fp_hpp, fp_cpp, _globalNames, *this);3702build_map(output_right_op);3703// Construct the table of rule names3704OutputRuleName output_rule_name(fp_hpp, fp_cpp, _globalNames, *this);3705build_map(output_rule_name);3706// Construct the boolean table for subsumed operands3707OutputSwallowed output_swallowed(fp_hpp, fp_cpp, _globalNames, *this);3708build_map(output_swallowed);3709// // // Preserve in case we decide to use this table instead of another3710//// Construct the boolean table for instruction chain rules3711//OutputInstChainRule output_inst_chain(fp_hpp, fp_cpp, _globalNames, *this);3712//build_map(output_inst_chain);37133714}371537163717//---------------------------buildMachOperGenerator---------------------------37183719// Recurse through match tree, building path through corresponding state tree,3720// Until we reach the constant we are looking for.3721static void path_to_constant(FILE *fp, FormDict &globals,3722MatchNode *mnode, uint idx) {3723if ( ! mnode) return;37243725unsigned position = 0;3726const char *result = NULL;3727const char *name = NULL;3728const char *optype = NULL;37293730// Base Case: access constant in ideal node linked to current state node3731// Each type of constant has its own access function3732if ( (mnode->_lChild == NULL) && (mnode->_rChild == NULL)3733&& mnode->base_operand(position, globals, result, name, optype) ) {3734if ( strcmp(optype,"ConI") == 0 ) {3735fprintf(fp, "_leaf->get_int()");3736} else if ( (strcmp(optype,"ConP") == 0) ) {3737fprintf(fp, "_leaf->bottom_type()->is_ptr()");3738} else if ( (strcmp(optype,"ConN") == 0) ) {3739fprintf(fp, "_leaf->bottom_type()->is_narrowoop()");3740} else if ( (strcmp(optype,"ConNKlass") == 0) ) {3741fprintf(fp, "_leaf->bottom_type()->is_narrowklass()");3742} else if ( (strcmp(optype,"ConF") == 0) ) {3743fprintf(fp, "_leaf->getf()");3744} else if ( (strcmp(optype,"ConD") == 0) ) {3745fprintf(fp, "_leaf->getd()");3746} else if ( (strcmp(optype,"ConL") == 0) ) {3747fprintf(fp, "_leaf->get_long()");3748} else if ( (strcmp(optype,"Con")==0) ) {3749// !!!!! - Update if adding a machine-independent constant type3750fprintf(fp, "_leaf->get_int()");3751assert( false, "Unsupported constant type, pointer or indefinite");3752} else if ( (strcmp(optype,"Bool") == 0) ) {3753fprintf(fp, "_leaf->as_Bool()->_test._test");3754} else {3755assert( false, "Unsupported constant type");3756}3757return;3758}37593760// If constant is in left child, build path and recurse3761uint lConsts = (mnode->_lChild) ? (mnode->_lChild->num_consts(globals) ) : 0;3762uint rConsts = (mnode->_rChild) ? (mnode->_rChild->num_consts(globals) ) : 0;3763if ( (mnode->_lChild) && (lConsts > idx) ) {3764fprintf(fp, "_kids[0]->");3765path_to_constant(fp, globals, mnode->_lChild, idx);3766return;3767}3768// If constant is in right child, build path and recurse3769if ( (mnode->_rChild) && (rConsts > (idx - lConsts) ) ) {3770idx = idx - lConsts;3771fprintf(fp, "_kids[1]->");3772path_to_constant(fp, globals, mnode->_rChild, idx);3773return;3774}3775assert( false, "ShouldNotReachHere()");3776}37773778// Generate code that is executed when generating a specific Machine Operand3779static void genMachOperCase(FILE *fp, FormDict &globalNames, ArchDesc &AD,3780OperandForm &op) {3781const char *opName = op._ident;3782const char *opEnumName = AD.machOperEnum(opName);3783uint num_consts = op.num_consts(globalNames);37843785// Generate the case statement for this opcode3786fprintf(fp, " case %s:", opEnumName);3787fprintf(fp, "\n return new %sOper(", opName);3788// Access parameters for constructor from the stat object3789//3790// Build access to condition code value3791if ( (num_consts > 0) ) {3792uint i = 0;3793path_to_constant(fp, globalNames, op._matrule, i);3794for ( i = 1; i < num_consts; ++i ) {3795fprintf(fp, ", ");3796path_to_constant(fp, globalNames, op._matrule, i);3797}3798}3799fprintf(fp, " );\n");3800}380138023803// Build switch to invoke "new" MachNode or MachOper3804void ArchDesc::buildMachOperGenerator(FILE *fp_cpp) {3805int idx = 0;38063807// Build switch to invoke 'new' for a specific MachOper3808fprintf(fp_cpp, "\n");3809fprintf(fp_cpp, "\n");3810fprintf(fp_cpp,3811"//------------------------- MachOper Generator ---------------\n");3812fprintf(fp_cpp,3813"// A switch statement on the dense-packed user-defined type system\n"3814"// that invokes 'new' on the corresponding class constructor.\n");3815fprintf(fp_cpp, "\n");3816fprintf(fp_cpp, "MachOper *State::MachOperGenerator");3817fprintf(fp_cpp, "(int opcode)");3818fprintf(fp_cpp, "{\n");3819fprintf(fp_cpp, "\n");3820fprintf(fp_cpp, " switch(opcode) {\n");38213822// Place all user-defined operands into the mapping3823_operands.reset();3824int opIndex = 0;3825OperandForm *op;3826for( ; (op = (OperandForm*)_operands.iter()) != NULL; ) {3827// Ensure this is a machine-world instruction3828if ( op->ideal_only() ) continue;38293830genMachOperCase(fp_cpp, _globalNames, *this, *op);3831};38323833// Do not iterate over operand classes for the operand generator!!!38343835// Place all internal operands into the mapping3836_internalOpNames.reset();3837const char *iopn;3838for( ; (iopn = _internalOpNames.iter()) != NULL; ) {3839const char *opEnumName = machOperEnum(iopn);3840// Generate the case statement for this opcode3841fprintf(fp_cpp, " case %s:", opEnumName);3842fprintf(fp_cpp, " return NULL;\n");3843};38443845// Generate the default case for switch(opcode)3846fprintf(fp_cpp, " \n");3847fprintf(fp_cpp, " default:\n");3848fprintf(fp_cpp, " fprintf(stderr, \"Default MachOper Generator invoked for: \\n\");\n");3849fprintf(fp_cpp, " fprintf(stderr, \" opcode = %cd\\n\", opcode);\n", '%');3850fprintf(fp_cpp, " break;\n");3851fprintf(fp_cpp, " }\n");38523853// Generate the closing for method Matcher::MachOperGenerator3854fprintf(fp_cpp, " return NULL;\n");3855fprintf(fp_cpp, "};\n");3856}385738583859//---------------------------buildMachNode-------------------------------------3860// Build a new MachNode, for MachNodeGenerator or cisc-spilling3861void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *indent) {3862const char *opType = NULL;3863const char *opClass = inst->_ident;38643865// Create the MachNode object3866fprintf(fp_cpp, "%s %sNode *node = new %sNode();\n",indent, opClass,opClass);38673868if ( (inst->num_post_match_opnds() != 0) ) {3869// Instruction that contains operands which are not in match rule.3870//3871// Check if the first post-match component may be an interesting def3872bool dont_care = false;3873ComponentList &comp_list = inst->_components;3874Component *comp = NULL;3875comp_list.reset();3876if ( comp_list.match_iter() != NULL ) dont_care = true;38773878// Insert operands that are not in match-rule.3879// Only insert a DEF if the do_care flag is set3880comp_list.reset();3881while ( (comp = comp_list.post_match_iter()) ) {3882// Check if we don't care about DEFs or KILLs that are not USEs3883if ( dont_care && (! comp->isa(Component::USE)) ) {3884continue;3885}3886dont_care = true;3887// For each operand not in the match rule, call MachOperGenerator3888// with the enum for the opcode that needs to be built.3889ComponentList clist = inst->_components;3890int index = clist.operand_position(comp->_name, comp->_usedef, inst);3891const char *opcode = machOperEnum(comp->_type);3892fprintf(fp_cpp, "%s node->set_opnd_array(%d, ", indent, index);3893fprintf(fp_cpp, "MachOperGenerator(%s));\n", opcode);3894}3895}3896else if ( inst->is_chain_of_constant(_globalNames, opType) ) {3897// An instruction that chains from a constant!3898// In this case, we need to subsume the constant into the node3899// at operand position, oper_input_base().3900//3901// Fill in the constant3902fprintf(fp_cpp, "%s node->_opnd_array[%d] = ", indent,3903inst->oper_input_base(_globalNames));3904// #####3905// Check for multiple constants and then fill them in.3906// Just like MachOperGenerator3907const char *opName = inst->_matrule->_rChild->_opType;3908fprintf(fp_cpp, "new %sOper(", opName);3909// Grab operand form3910OperandForm *op = (_globalNames[opName])->is_operand();3911// Look up the number of constants3912uint num_consts = op->num_consts(_globalNames);3913if ( (num_consts > 0) ) {3914uint i = 0;3915path_to_constant(fp_cpp, _globalNames, op->_matrule, i);3916for ( i = 1; i < num_consts; ++i ) {3917fprintf(fp_cpp, ", ");3918path_to_constant(fp_cpp, _globalNames, op->_matrule, i);3919}3920}3921fprintf(fp_cpp, " );\n");3922// #####3923}39243925// Fill in the bottom_type where requested3926if (inst->captures_bottom_type(_globalNames)) {3927if (strncmp("MachCall", inst->mach_base_class(_globalNames), strlen("MachCall"))) {3928fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);3929}3930}3931if( inst->is_ideal_if() ) {3932fprintf(fp_cpp, "%s node->_prob = _leaf->as_If()->_prob;\n", indent);3933fprintf(fp_cpp, "%s node->_fcnt = _leaf->as_If()->_fcnt;\n", indent);3934}3935if (inst->is_ideal_halt()) {3936fprintf(fp_cpp, "%s node->_halt_reason = _leaf->as_Halt()->_halt_reason;\n", indent);3937fprintf(fp_cpp, "%s node->_reachable = _leaf->as_Halt()->_reachable;\n", indent);3938}3939if (inst->is_ideal_jump()) {3940fprintf(fp_cpp, "%s node->_probs = _leaf->as_Jump()->_probs;\n", indent);3941}3942if( inst->is_ideal_fastlock() ) {3943fprintf(fp_cpp, "%s node->_counters = _leaf->as_FastLock()->counters();\n", indent);3944fprintf(fp_cpp, "%s node->_rtm_counters = _leaf->as_FastLock()->rtm_counters();\n", indent);3945fprintf(fp_cpp, "%s node->_stack_rtm_counters = _leaf->as_FastLock()->stack_rtm_counters();\n", indent);3946}39473948}39493950//---------------------------declare_cisc_version------------------------------3951// Build CISC version of this instruction3952void InstructForm::declare_cisc_version(ArchDesc &AD, FILE *fp_hpp) {3953if( AD.can_cisc_spill() ) {3954InstructForm *inst_cisc = cisc_spill_alternate();3955if (inst_cisc != NULL) {3956fprintf(fp_hpp, " virtual int cisc_operand() const { return %d; }\n", cisc_spill_operand());3957fprintf(fp_hpp, " virtual MachNode *cisc_version(int offset);\n");3958fprintf(fp_hpp, " virtual void use_cisc_RegMask();\n");3959fprintf(fp_hpp, " virtual const RegMask *cisc_RegMask() const { return _cisc_RegMask; }\n");3960}3961}3962}39633964//---------------------------define_cisc_version-------------------------------3965// Build CISC version of this instruction3966bool InstructForm::define_cisc_version(ArchDesc &AD, FILE *fp_cpp) {3967InstructForm *inst_cisc = this->cisc_spill_alternate();3968if( AD.can_cisc_spill() && (inst_cisc != NULL) ) {3969const char *name = inst_cisc->_ident;3970assert( inst_cisc->num_opnds() == this->num_opnds(), "Must have same number of operands");3971OperandForm *cisc_oper = AD.cisc_spill_operand();3972assert( cisc_oper != NULL, "insanity check");3973const char *cisc_oper_name = cisc_oper->_ident;3974assert( cisc_oper_name != NULL, "insanity check");3975//3976// Set the correct reg_mask_or_stack for the cisc operand3977fprintf(fp_cpp, "\n");3978fprintf(fp_cpp, "void %sNode::use_cisc_RegMask() {\n", this->_ident);3979// Lookup the correct reg_mask_or_stack3980const char *reg_mask_name = cisc_reg_mask_name();3981fprintf(fp_cpp, " _cisc_RegMask = &STACK_OR_%s;\n", reg_mask_name);3982fprintf(fp_cpp, "}\n");3983//3984// Construct CISC version of this instruction3985fprintf(fp_cpp, "\n");3986fprintf(fp_cpp, "// Build CISC version of this instruction\n");3987fprintf(fp_cpp, "MachNode *%sNode::cisc_version(int offset) {\n", this->_ident);3988// Create the MachNode object3989fprintf(fp_cpp, " %sNode *node = new %sNode();\n", name, name);3990// Fill in the bottom_type where requested3991if ( this->captures_bottom_type(AD.globalNames()) ) {3992fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");3993}39943995uint cur_num_opnds = num_opnds();3996if (cur_num_opnds > 1 && cur_num_opnds != num_unique_opnds()) {3997fprintf(fp_cpp," node->_num_opnds = %d;\n", num_unique_opnds());3998}39994000fprintf(fp_cpp, "\n");4001fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n");4002fprintf(fp_cpp, " fill_new_machnode(node);\n");4003// Construct operand to access [stack_pointer + offset]4004fprintf(fp_cpp, " // Construct operand to access [stack_pointer + offset]\n");4005fprintf(fp_cpp, " node->set_opnd_array(cisc_operand(), new %sOper(offset));\n", cisc_oper_name);4006fprintf(fp_cpp, "\n");40074008// Return result and exit scope4009fprintf(fp_cpp, " return node;\n");4010fprintf(fp_cpp, "}\n");4011fprintf(fp_cpp, "\n");4012return true;4013}4014return false;4015}40164017//---------------------------declare_short_branch_methods----------------------4018// Build prototypes for short branch methods4019void InstructForm::declare_short_branch_methods(FILE *fp_hpp) {4020if (has_short_branch_form()) {4021fprintf(fp_hpp, " virtual MachNode *short_branch_version();\n");4022}4023}40244025//---------------------------define_short_branch_methods-----------------------4026// Build definitions for short branch methods4027bool InstructForm::define_short_branch_methods(ArchDesc &AD, FILE *fp_cpp) {4028if (has_short_branch_form()) {4029InstructForm *short_branch = short_branch_form();4030const char *name = short_branch->_ident;40314032// Construct short_branch_version() method.4033fprintf(fp_cpp, "// Build short branch version of this instruction\n");4034fprintf(fp_cpp, "MachNode *%sNode::short_branch_version() {\n", this->_ident);4035// Create the MachNode object4036fprintf(fp_cpp, " %sNode *node = new %sNode();\n", name, name);4037if( is_ideal_if() ) {4038fprintf(fp_cpp, " node->_prob = _prob;\n");4039fprintf(fp_cpp, " node->_fcnt = _fcnt;\n");4040}4041// Fill in the bottom_type where requested4042if ( this->captures_bottom_type(AD.globalNames()) ) {4043fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");4044}40454046fprintf(fp_cpp, "\n");4047// Short branch version must use same node index for access4048// through allocator's tables4049fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n");4050fprintf(fp_cpp, " fill_new_machnode(node);\n");40514052// Return result and exit scope4053fprintf(fp_cpp, " return node;\n");4054fprintf(fp_cpp, "}\n");4055fprintf(fp_cpp,"\n");4056return true;4057}4058return false;4059}406040614062//---------------------------buildMachNodeGenerator----------------------------4063// Build switch to invoke appropriate "new" MachNode for an opcode4064void ArchDesc::buildMachNodeGenerator(FILE *fp_cpp) {40654066// Build switch to invoke 'new' for a specific MachNode4067fprintf(fp_cpp, "\n");4068fprintf(fp_cpp, "\n");4069fprintf(fp_cpp,4070"//------------------------- MachNode Generator ---------------\n");4071fprintf(fp_cpp,4072"// A switch statement on the dense-packed user-defined type system\n"4073"// that invokes 'new' on the corresponding class constructor.\n");4074fprintf(fp_cpp, "\n");4075fprintf(fp_cpp, "MachNode *State::MachNodeGenerator");4076fprintf(fp_cpp, "(int opcode)");4077fprintf(fp_cpp, "{\n");4078fprintf(fp_cpp, " switch(opcode) {\n");40794080// Provide constructor for all user-defined instructions4081_instructions.reset();4082int opIndex = operandFormCount();4083InstructForm *inst;4084for( ; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {4085// Ensure that matrule is defined.4086if ( inst->_matrule == NULL ) continue;40874088int opcode = opIndex++;4089const char *opClass = inst->_ident;4090char *opType = NULL;40914092// Generate the case statement for this instruction4093fprintf(fp_cpp, " case %s_rule:", opClass);40944095// Start local scope4096fprintf(fp_cpp, " {\n");4097// Generate code to construct the new MachNode4098buildMachNode(fp_cpp, inst, " ");4099// Return result and exit scope4100fprintf(fp_cpp, " return node;\n");4101fprintf(fp_cpp, " }\n");4102}41034104// Generate the default case for switch(opcode)4105fprintf(fp_cpp, " \n");4106fprintf(fp_cpp, " default:\n");4107fprintf(fp_cpp, " fprintf(stderr, \"Default MachNode Generator invoked for: \\n\");\n");4108fprintf(fp_cpp, " fprintf(stderr, \" opcode = %cd\\n\", opcode);\n", '%');4109fprintf(fp_cpp, " break;\n");4110fprintf(fp_cpp, " };\n");41114112// Generate the closing for method Matcher::MachNodeGenerator4113fprintf(fp_cpp, " return NULL;\n");4114fprintf(fp_cpp, "}\n");4115}411641174118//---------------------------buildInstructMatchCheck--------------------------4119// Output the method to Matcher which checks whether or not a specific4120// instruction has a matching rule for the host architecture.4121void ArchDesc::buildInstructMatchCheck(FILE *fp_cpp) const {4122fprintf(fp_cpp, "\n\n");4123fprintf(fp_cpp, "const bool Matcher::has_match_rule(int opcode) {\n");4124fprintf(fp_cpp, " assert(_last_machine_leaf < opcode && opcode < _last_opcode, \"opcode in range\");\n");4125fprintf(fp_cpp, " return _hasMatchRule[opcode];\n");4126fprintf(fp_cpp, "}\n\n");41274128fprintf(fp_cpp, "const bool Matcher::_hasMatchRule[_last_opcode] = {\n");4129int i;4130for (i = 0; i < _last_opcode - 1; i++) {4131fprintf(fp_cpp, " %-5s, // %s\n",4132_has_match_rule[i] ? "true" : "false",4133NodeClassNames[i]);4134}4135fprintf(fp_cpp, " %-5s // %s\n",4136_has_match_rule[i] ? "true" : "false",4137NodeClassNames[i]);4138fprintf(fp_cpp, "};\n");4139}41404141//---------------------------buildFrameMethods---------------------------------4142// Output the methods to Matcher which specify frame behavior4143void ArchDesc::buildFrameMethods(FILE *fp_cpp) {4144fprintf(fp_cpp,"\n\n");4145// Sync Stack Slots4146fprintf(fp_cpp,"int Compile::sync_stack_slots() const { return %s; }\n\n",4147_frame->_sync_stack_slots);4148// Java Stack Alignment4149fprintf(fp_cpp,"uint Matcher::stack_alignment_in_bytes() { return %s; }\n\n",4150_frame->_alignment);4151// Java Return Address Location4152fprintf(fp_cpp,"OptoReg::Name Matcher::return_addr() const {");4153if (_frame->_return_addr_loc) {4154fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4155_frame->_return_addr);4156}4157else {4158fprintf(fp_cpp," return OptoReg::stack2reg(%s); }\n\n",4159_frame->_return_addr);4160}4161// varargs C out slots killed4162fprintf(fp_cpp,"uint Compile::varargs_C_out_slots_killed() const ");4163fprintf(fp_cpp,"{ return %s; }\n\n", _frame->_varargs_C_out_slots_killed);4164// Java Return Value Location4165fprintf(fp_cpp,"OptoRegPair Matcher::return_value(uint ideal_reg) {\n");4166fprintf(fp_cpp,"%s\n", _frame->_return_value);4167fprintf(fp_cpp,"}\n\n");4168// Native Return Value Location4169fprintf(fp_cpp,"OptoRegPair Matcher::c_return_value(uint ideal_reg) {\n");4170fprintf(fp_cpp,"%s\n", _frame->_c_return_value);4171fprintf(fp_cpp,"}\n\n");41724173// Inline Cache Register, mask definition, and encoding4174fprintf(fp_cpp,"OptoReg::Name Matcher::inline_cache_reg() {");4175fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4176_frame->_inline_cache_reg);4177fprintf(fp_cpp,"int Matcher::inline_cache_reg_encode() {");4178fprintf(fp_cpp," return _regEncode[inline_cache_reg()]; }\n\n");41794180// Interpreter's Frame Pointer Register4181fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_frame_pointer_reg() {");4182if (_frame->_interpreter_frame_pointer_reg == NULL)4183fprintf(fp_cpp," return OptoReg::Bad; }\n\n");4184else4185fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4186_frame->_interpreter_frame_pointer_reg);41874188// Frame Pointer definition4189/* CNC - I can not contemplate having a different frame pointer between4190Java and native code; makes my head hurt to think about it.4191fprintf(fp_cpp,"OptoReg::Name Matcher::frame_pointer() const {");4192fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4193_frame->_frame_pointer);4194*/4195// (Native) Frame Pointer definition4196fprintf(fp_cpp,"OptoReg::Name Matcher::c_frame_pointer() const {");4197fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4198_frame->_frame_pointer);41994200// Number of callee-save + always-save registers for calling convention4201fprintf(fp_cpp, "// Number of callee-save + always-save registers\n");4202fprintf(fp_cpp, "int Matcher::number_of_saved_registers() {\n");4203RegDef *rdef;4204int nof_saved_registers = 0;4205_register->reset_RegDefs();4206while( (rdef = _register->iter_RegDefs()) != NULL ) {4207if( !strcmp(rdef->_callconv, "SOE") || !strcmp(rdef->_callconv, "AS") )4208++nof_saved_registers;4209}4210fprintf(fp_cpp, " return %d;\n", nof_saved_registers);4211fprintf(fp_cpp, "};\n\n");4212}42134214421542164217static int PrintAdlcCisc = 0;4218//---------------------------identify_cisc_spilling----------------------------4219// Get info for the CISC_oracle and MachNode::cisc_version()4220void ArchDesc::identify_cisc_spill_instructions() {42214222if (_frame == NULL)4223return;42244225// Find the user-defined operand for cisc-spilling4226if( _frame->_cisc_spilling_operand_name != NULL ) {4227const Form *form = _globalNames[_frame->_cisc_spilling_operand_name];4228OperandForm *oper = form ? form->is_operand() : NULL;4229// Verify the user's suggestion4230if( oper != NULL ) {4231// Ensure that match field is defined.4232if ( oper->_matrule != NULL ) {4233MatchRule &mrule = *oper->_matrule;4234if( strcmp(mrule._opType,"AddP") == 0 ) {4235MatchNode *left = mrule._lChild;4236MatchNode *right= mrule._rChild;4237if( left != NULL && right != NULL ) {4238const Form *left_op = _globalNames[left->_opType]->is_operand();4239const Form *right_op = _globalNames[right->_opType]->is_operand();4240if( (left_op != NULL && right_op != NULL)4241&& (left_op->interface_type(_globalNames) == Form::register_interface)4242&& (right_op->interface_type(_globalNames) == Form::constant_interface) ) {4243// Successfully verified operand4244set_cisc_spill_operand( oper );4245if( _cisc_spill_debug ) {4246fprintf(stderr, "\n\nVerified CISC-spill operand %s\n\n", oper->_ident);4247}4248}4249}4250}4251}4252}4253}42544255if( cisc_spill_operand() != NULL ) {4256// N^2 comparison of instructions looking for a cisc-spilling version4257_instructions.reset();4258InstructForm *instr;4259for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {4260// Ensure that match field is defined.4261if ( instr->_matrule == NULL ) continue;42624263MatchRule &mrule = *instr->_matrule;4264Predicate *pred = instr->build_predicate();42654266// Grab the machine type of the operand4267const char *rootOp = instr->_ident;4268mrule._machType = rootOp;42694270// Find result type for match4271const char *result = instr->reduce_result();42724273if( PrintAdlcCisc ) fprintf(stderr, " new instruction %s \n", instr->_ident ? instr->_ident : " ");4274bool found_cisc_alternate = false;4275_instructions.reset2();4276InstructForm *instr2;4277for( ; !found_cisc_alternate && (instr2 = (InstructForm*)_instructions.iter2()) != NULL; ) {4278// Ensure that match field is defined.4279if( PrintAdlcCisc ) fprintf(stderr, " instr2 == %s \n", instr2->_ident ? instr2->_ident : " ");4280if ( instr2->_matrule != NULL4281&& (instr != instr2 ) // Skip self4282&& (instr2->reduce_result() != NULL) // want same result4283&& (strcmp(result, instr2->reduce_result()) == 0)) {4284MatchRule &mrule2 = *instr2->_matrule;4285Predicate *pred2 = instr2->build_predicate();4286found_cisc_alternate = instr->cisc_spills_to(*this, instr2);4287}4288}4289}4290}4291}42924293//---------------------------build_cisc_spilling-------------------------------4294// Get info for the CISC_oracle and MachNode::cisc_version()4295void ArchDesc::build_cisc_spill_instructions(FILE *fp_hpp, FILE *fp_cpp) {4296// Output the table for cisc spilling4297fprintf(fp_cpp, "// The following instructions can cisc-spill\n");4298_instructions.reset();4299InstructForm *inst = NULL;4300for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {4301// Ensure this is a machine-world instruction4302if ( inst->ideal_only() ) continue;4303const char *inst_name = inst->_ident;4304int operand = inst->cisc_spill_operand();4305if( operand != AdlcVMDeps::Not_cisc_spillable ) {4306InstructForm *inst2 = inst->cisc_spill_alternate();4307fprintf(fp_cpp, "// %s can cisc-spill operand %d to %s\n", inst->_ident, operand, inst2->_ident);4308}4309}4310fprintf(fp_cpp, "\n\n");4311}43124313//---------------------------identify_short_branches----------------------------4314// Get info for our short branch replacement oracle.4315void ArchDesc::identify_short_branches() {4316// Walk over all instructions, checking to see if they match a short4317// branching alternate.4318_instructions.reset();4319InstructForm *instr;4320while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {4321// The instruction must have a match rule.4322if (instr->_matrule != NULL &&4323instr->is_short_branch()) {43244325_instructions.reset2();4326InstructForm *instr2;4327while( (instr2 = (InstructForm*)_instructions.iter2()) != NULL ) {4328instr2->check_branch_variant(*this, instr);4329}4330}4331}4332}433343344335//---------------------------identify_unique_operands---------------------------4336// Identify unique operands.4337void ArchDesc::identify_unique_operands() {4338// Walk over all instructions.4339_instructions.reset();4340InstructForm *instr;4341while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {4342// Ensure this is a machine-world instruction4343if (!instr->ideal_only()) {4344instr->set_unique_opnds();4345}4346}4347}434843494350