Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/adlc/output_c.cpp
32285 views
/*1* Copyright (c) 1998, 2018, 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 <=726#ifdef SPARC72764728#else72932730#endif731) {732fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");733fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask & in2._mask);\n");734fprintf(fp_cpp, "}\n\n");735fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");736fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask | in2._mask);\n");737fprintf(fp_cpp, "}\n\n");738}739else {740uint l;741uint masklen = (_pipeline->_maxcycleused + 31) >> 5;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\n", l, l, l < masklen ? ", " : "");746fprintf(fp_cpp, ");\n");747fprintf(fp_cpp, "}\n\n");748fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");749fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(");750for (l = 1; l <= masklen; l++)751fprintf(fp_cpp, "in1._mask%d | in2._mask%d%s", l, l, l < masklen ? ", " : "");752fprintf(fp_cpp, ");\n");753fprintf(fp_cpp, "}\n\n");754fprintf(fp_cpp, "void Pipeline_Use_Cycle_Mask::Or(const Pipeline_Use_Cycle_Mask &in2) {\n ");755for (l = 1; l <= masklen; l++)756fprintf(fp_cpp, " _mask%d |= in2._mask%d;", l, l);757fprintf(fp_cpp, "\n}\n\n");758}759760/* Get the length of all the resource names */761for (_pipeline->_reslist.reset(), resourcenamelen = 0;762(resourcename = _pipeline->_reslist.iter()) != NULL;763resourcenamelen += (int)strlen(resourcename));764765// Create the pipeline class description766767fprintf(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");768fprintf(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");769770fprintf(fp_cpp, "const Pipeline_Use_Element Pipeline_Use::elaborated_elements[%d] = {\n", _pipeline->_rescount);771for (int i1 = 0; i1 < _pipeline->_rescount; i1++) {772fprintf(fp_cpp, " Pipeline_Use_Element(0, %d, %d, false, Pipeline_Use_Cycle_Mask(", i1, i1);773uint masklen = (_pipeline->_maxcycleused + 31) >> 5;774for (int i2 = masklen-1; i2 >= 0; i2--)775fprintf(fp_cpp, "0%s", i2 > 0 ? ", " : "");776fprintf(fp_cpp, "))%s\n", i1 < (_pipeline->_rescount-1) ? "," : "");777}778fprintf(fp_cpp, "};\n\n");779780fprintf(fp_cpp, "const Pipeline_Use Pipeline_Use::elaborated_use(0, 0, %d, (Pipeline_Use_Element *)&elaborated_elements[0]);\n\n",781_pipeline->_rescount);782783for (_pipeline->_classlist.reset(); (classname = _pipeline->_classlist.iter()) != NULL; ) {784fprintf(fp_cpp, "\n");785fprintf(fp_cpp, "// Pipeline Class \"%s\"\n", classname);786PipeClassForm *pipeclass = _pipeline->_classdict[classname]->is_pipeclass();787int maxWriteStage = -1;788int maxMoreInstrs = 0;789int paramcount = 0;790int i = 0;791const char *paramname;792int resource_count = (_pipeline->_rescount + 3) >> 2;793794// Scan the operands, looking for last output stage and number of inputs795for (pipeclass->_parameters.reset(); (paramname = pipeclass->_parameters.iter()) != NULL; ) {796const PipeClassOperandForm *pipeopnd =797(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];798if (pipeopnd) {799if (pipeopnd->_iswrite) {800int stagenum = _pipeline->_stages.index(pipeopnd->_stage);801int moreinsts = pipeopnd->_more_instrs;802if ((maxWriteStage+maxMoreInstrs) < (stagenum+moreinsts)) {803maxWriteStage = stagenum;804maxMoreInstrs = moreinsts;805}806}807}808809if (i++ > 0 || (pipeopnd && !pipeopnd->isWrite()))810paramcount++;811}812813// Create the list of stages for the operands that are read814// Note that we will build a NameList to reduce the number of copies815816int pipeline_reads_index = pipeline_reads_initializer(fp_cpp, pipeline_reads, pipeclass);817818int pipeline_res_stages_index = pipeline_res_stages_initializer(819fp_cpp, _pipeline, pipeline_res_stages, pipeclass);820821int pipeline_res_cycles_index = pipeline_res_cycles_initializer(822fp_cpp, _pipeline, pipeline_res_cycles, pipeclass);823824int pipeline_res_mask_index = pipeline_res_mask_initializer(825fp_cpp, _pipeline, pipeline_res_masks, pipeline_res_args, pipeclass);826827#if 0828// Process the Resources829const PipeClassResourceForm *piperesource;830831unsigned resources_used = 0;832unsigned exclusive_resources_used = 0;833unsigned resource_groups = 0;834for (pipeclass->_resUsage.reset();835(piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {836int used_mask = _pipeline->_resdict[piperesource->_resource]->is_resource()->mask();837if (used_mask)838resource_groups++;839resources_used |= used_mask;840if ((used_mask & (used_mask-1)) == 0)841exclusive_resources_used |= used_mask;842}843844if (resource_groups > 0) {845fprintf(fp_cpp, "static const uint pipeline_res_or_masks_%03d[%d] = {",846pipeclass->_num, resource_groups);847for (pipeclass->_resUsage.reset(), i = 1;848(piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL;849i++ ) {850int used_mask = _pipeline->_resdict[piperesource->_resource]->is_resource()->mask();851if (used_mask) {852fprintf(fp_cpp, " 0x%0*x%c", resource_count, used_mask, i < (int)resource_groups ? ',' : ' ');853}854}855fprintf(fp_cpp, "};\n\n");856}857#endif858859// Create the pipeline class description860fprintf(fp_cpp, "static const Pipeline pipeline_class_%03d(",861pipeclass->_num);862if (maxWriteStage < 0)863fprintf(fp_cpp, "(uint)stage_undefined");864else if (maxMoreInstrs == 0)865fprintf(fp_cpp, "(uint)stage_%s", _pipeline->_stages.name(maxWriteStage));866else867fprintf(fp_cpp, "((uint)stage_%s)+%d", _pipeline->_stages.name(maxWriteStage), maxMoreInstrs);868fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s, %s,\n",869paramcount,870pipeclass->hasFixedLatency() ? "true" : "false",871pipeclass->fixedLatency(),872pipeclass->InstructionCount(),873pipeclass->hasBranchDelay() ? "true" : "false",874pipeclass->hasMultipleBundles() ? "true" : "false",875pipeclass->forceSerialization() ? "true" : "false",876pipeclass->mayHaveNoCode() ? "true" : "false" );877if (paramcount > 0) {878fprintf(fp_cpp, "\n (enum machPipelineStages * const) pipeline_reads_%03d,\n ",879pipeline_reads_index+1);880}881else882fprintf(fp_cpp, " NULL,");883fprintf(fp_cpp, " (enum machPipelineStages * const) pipeline_res_stages_%03d,\n",884pipeline_res_stages_index+1);885fprintf(fp_cpp, " (uint * const) pipeline_res_cycles_%03d,\n",886pipeline_res_cycles_index+1);887fprintf(fp_cpp, " Pipeline_Use(%s, (Pipeline_Use_Element *)",888pipeline_res_args.name(pipeline_res_mask_index));889if (strlen(pipeline_res_masks.name(pipeline_res_mask_index)) > 0)890fprintf(fp_cpp, "&pipeline_res_mask_%03d[0]",891pipeline_res_mask_index+1);892else893fprintf(fp_cpp, "NULL");894fprintf(fp_cpp, "));\n");895}896897// Generate the Node::latency method if _pipeline defined898fprintf(fp_cpp, "\n");899fprintf(fp_cpp, "//------------------Inter-Instruction Latency--------------------------------\n");900fprintf(fp_cpp, "uint Node::latency(uint i) {\n");901if (_pipeline) {902#if 0903fprintf(fp_cpp, "#ifndef PRODUCT\n");904fprintf(fp_cpp, " if (TraceOptoOutput) {\n");905fprintf(fp_cpp, " tty->print(\"# %%4d->latency(%%d)\\n\", _idx, i);\n");906fprintf(fp_cpp, " }\n");907fprintf(fp_cpp, "#endif\n");908#endif909fprintf(fp_cpp, " uint j;\n");910fprintf(fp_cpp, " // verify in legal range for inputs\n");911fprintf(fp_cpp, " assert(i < len(), \"index not in range\");\n\n");912fprintf(fp_cpp, " // verify input is not null\n");913fprintf(fp_cpp, " Node *pred = in(i);\n");914fprintf(fp_cpp, " if (!pred)\n return %d;\n\n",915non_operand_latency);916fprintf(fp_cpp, " if (pred->is_Proj())\n pred = pred->in(0);\n\n");917fprintf(fp_cpp, " // if either node does not have pipeline info, use default\n");918fprintf(fp_cpp, " const Pipeline *predpipe = pred->pipeline();\n");919fprintf(fp_cpp, " assert(predpipe, \"no predecessor pipeline info\");\n\n");920fprintf(fp_cpp, " if (predpipe->hasFixedLatency())\n return predpipe->fixedLatency();\n\n");921fprintf(fp_cpp, " const Pipeline *currpipe = pipeline();\n");922fprintf(fp_cpp, " assert(currpipe, \"no pipeline info\");\n\n");923fprintf(fp_cpp, " if (!is_Mach())\n return %d;\n\n",924node_latency);925fprintf(fp_cpp, " const MachNode *m = as_Mach();\n");926fprintf(fp_cpp, " j = m->oper_input_base();\n");927fprintf(fp_cpp, " if (i < j)\n return currpipe->functional_unit_latency(%d, predpipe);\n\n",928non_operand_latency);929fprintf(fp_cpp, " // determine which operand this is in\n");930fprintf(fp_cpp, " uint n = m->num_opnds();\n");931fprintf(fp_cpp, " int delta = %d;\n\n",932non_operand_latency);933fprintf(fp_cpp, " uint k;\n");934fprintf(fp_cpp, " for (k = 1; k < n; k++) {\n");935fprintf(fp_cpp, " j += m->_opnds[k]->num_edges();\n");936fprintf(fp_cpp, " if (i < j)\n");937fprintf(fp_cpp, " break;\n");938fprintf(fp_cpp, " }\n");939fprintf(fp_cpp, " if (k < n)\n");940fprintf(fp_cpp, " delta = currpipe->operand_latency(k,predpipe);\n\n");941fprintf(fp_cpp, " return currpipe->functional_unit_latency(delta, predpipe);\n");942}943else {944fprintf(fp_cpp, " // assert(false, \"pipeline functionality is not defined\");\n");945fprintf(fp_cpp, " return %d;\n",946non_operand_latency);947}948fprintf(fp_cpp, "}\n\n");949950// Output the list of nop nodes951fprintf(fp_cpp, "// Descriptions for emitting different functional unit nops\n");952const char *nop;953int nopcnt = 0;954for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; nopcnt++ );955956fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d], Compile *C) {\n", nopcnt);957int i = 0;958for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; i++ ) {959fprintf(fp_cpp, " nop_list[%d] = (MachNode *) new (C) %sNode();\n", i, nop);960}961fprintf(fp_cpp, "};\n\n");962fprintf(fp_cpp, "#ifndef PRODUCT\n");963fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n");964fprintf(fp_cpp, " static const char * bundle_flags[] = {\n");965fprintf(fp_cpp, " \"\",\n");966fprintf(fp_cpp, " \"use nop delay\",\n");967fprintf(fp_cpp, " \"use unconditional delay\",\n");968fprintf(fp_cpp, " \"use conditional delay\",\n");969fprintf(fp_cpp, " \"used in conditional delay\",\n");970fprintf(fp_cpp, " \"used in unconditional delay\",\n");971fprintf(fp_cpp, " \"used in all conditional delays\",\n");972fprintf(fp_cpp, " };\n\n");973974fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount);975for (i = 0; i < _pipeline->_rescount; i++)976fprintf(fp_cpp, " \"%s\"%c", _pipeline->_reslist.name(i), i < _pipeline->_rescount-1 ? ',' : ' ');977fprintf(fp_cpp, "};\n\n");978979// See if the same string is in the table980fprintf(fp_cpp, " bool needs_comma = false;\n\n");981fprintf(fp_cpp, " if (_flags) {\n");982fprintf(fp_cpp, " st->print(\"%%s\", bundle_flags[_flags]);\n");983fprintf(fp_cpp, " needs_comma = true;\n");984fprintf(fp_cpp, " };\n");985fprintf(fp_cpp, " if (instr_count()) {\n");986fprintf(fp_cpp, " st->print(\"%%s%%d instr%%s\", needs_comma ? \", \" : \"\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n");987fprintf(fp_cpp, " needs_comma = true;\n");988fprintf(fp_cpp, " };\n");989fprintf(fp_cpp, " uint r = resources_used();\n");990fprintf(fp_cpp, " if (r) {\n");991fprintf(fp_cpp, " st->print(\"%%sresource%%s:\", needs_comma ? \", \" : \"\", (r & (r-1)) != 0 ? \"s\" : \"\");\n");992fprintf(fp_cpp, " for (uint i = 0; i < %d; i++)\n", _pipeline->_rescount);993fprintf(fp_cpp, " if ((r & (1 << i)) != 0)\n");994fprintf(fp_cpp, " st->print(\" %%s\", resource_names[i]);\n");995fprintf(fp_cpp, " needs_comma = true;\n");996fprintf(fp_cpp, " };\n");997fprintf(fp_cpp, " st->print(\"\\n\");\n");998fprintf(fp_cpp, "}\n");999fprintf(fp_cpp, "#endif\n");1000}10011002// ---------------------------------------------------------------------------1003//------------------------------Utilities to build Instruction Classes--------1004// ---------------------------------------------------------------------------10051006static void defineOut_RegMask(FILE *fp, const char *node, const char *regMask) {1007fprintf(fp,"const RegMask &%sNode::out_RegMask() const { return (%s); }\n",1008node, regMask);1009}10101011static void print_block_index(FILE *fp, int inst_position) {1012assert( inst_position >= 0, "Instruction number less than zero");1013fprintf(fp, "block_index");1014if( inst_position != 0 ) {1015fprintf(fp, " - %d", inst_position);1016}1017}10181019// Scan the peepmatch and output a test for each instruction1020static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) {1021int parent = -1;1022int inst_position = 0;1023const char* inst_name = NULL;1024int input = 0;1025fprintf(fp, " // Check instruction sub-tree\n");1026pmatch->reset();1027for( pmatch->next_instruction( parent, inst_position, inst_name, input );1028inst_name != NULL;1029pmatch->next_instruction( parent, inst_position, inst_name, input ) ) {1030// If this is not a placeholder1031if( ! pmatch->is_placeholder() ) {1032// Define temporaries 'inst#', based on parent and parent's input index1033if( parent != -1 ) { // root was initialized1034fprintf(fp, " // Identify previous instruction if inside this block\n");1035fprintf(fp, " if( ");1036print_block_index(fp, inst_position);1037fprintf(fp, " > 0 ) {\n Node *n = block->get_node(");1038print_block_index(fp, inst_position);1039fprintf(fp, ");\n inst%d = (n->is_Mach()) ? ", inst_position);1040fprintf(fp, "n->as_Mach() : NULL;\n }\n");1041}10421043// When not the root1044// Test we have the correct instruction by comparing the rule.1045if( parent != -1 ) {1046fprintf(fp, " matches = matches && (inst%d != NULL) && (inst%d->rule() == %s_rule);\n",1047inst_position, inst_position, inst_name);1048}1049} else {1050// Check that user did not try to constrain a placeholder1051assert( ! pconstraint->constrains_instruction(inst_position),1052"fatal(): Can not constrain a placeholder instruction");1053}1054}1055}10561057// Build mapping for register indices, num_edges to input1058static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMatch *pmatch ) {1059int parent = -1;1060int inst_position = 0;1061const char* inst_name = NULL;1062int input = 0;1063fprintf(fp, " // Build map to register info\n");1064pmatch->reset();1065for( pmatch->next_instruction( parent, inst_position, inst_name, input );1066inst_name != NULL;1067pmatch->next_instruction( parent, inst_position, inst_name, input ) ) {1068// If this is not a placeholder1069if( ! pmatch->is_placeholder() ) {1070// Define temporaries 'inst#', based on self's inst_position1071InstructForm *inst = globals[inst_name]->is_instruction();1072if( inst != NULL ) {1073char inst_prefix[] = "instXXXX_";1074sprintf(inst_prefix, "inst%d_", inst_position);1075char receiver[] = "instXXXX->";1076sprintf(receiver, "inst%d->", inst_position);1077inst->index_temps( fp, globals, inst_prefix, receiver );1078}1079}1080}1081}10821083// Generate tests for the constraints1084static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch, PeepConstraint *pconstraint) {1085fprintf(fp, "\n");1086fprintf(fp, " // Check constraints on sub-tree-leaves\n");10871088// Build mapping from num_edges to local variables1089build_instruction_index_mapping( fp, globals, pmatch );10901091// Build constraint tests1092if( pconstraint != NULL ) {1093fprintf(fp, " matches = matches &&");1094bool first_constraint = true;1095while( pconstraint != NULL ) {1096// indentation and connecting '&&'1097const char *indentation = " ";1098fprintf(fp, "\n%s%s", indentation, (!first_constraint ? "&& " : " "));10991100// Only have '==' relation implemented1101if( strcmp(pconstraint->_relation,"==") != 0 ) {1102assert( false, "Unimplemented()" );1103}11041105// LEFT1106int left_index = pconstraint->_left_inst;1107const char *left_op = pconstraint->_left_op;1108// Access info on the instructions whose operands are compared1109InstructForm *inst_left = globals[pmatch->instruction_name(left_index)]->is_instruction();1110assert( inst_left, "Parser should guaranty this is an instruction");1111int left_op_base = inst_left->oper_input_base(globals);1112// Access info on the operands being compared1113int left_op_index = inst_left->operand_position(left_op, Component::USE);1114if( left_op_index == -1 ) {1115left_op_index = inst_left->operand_position(left_op, Component::DEF);1116if( left_op_index == -1 ) {1117left_op_index = inst_left->operand_position(left_op, Component::USE_DEF);1118}1119}1120assert( left_op_index != NameList::Not_in_list, "Did not find operand in instruction");1121ComponentList components_left = inst_left->_components;1122const char *left_comp_type = components_left.at(left_op_index)->_type;1123OpClassForm *left_opclass = globals[left_comp_type]->is_opclass();1124Form::InterfaceType left_interface_type = left_opclass->interface_type(globals);112511261127// RIGHT1128int right_op_index = -1;1129int right_index = pconstraint->_right_inst;1130const char *right_op = pconstraint->_right_op;1131if( right_index != -1 ) { // Match operand1132// Access info on the instructions whose operands are compared1133InstructForm *inst_right = globals[pmatch->instruction_name(right_index)]->is_instruction();1134assert( inst_right, "Parser should guaranty this is an instruction");1135int right_op_base = inst_right->oper_input_base(globals);1136// Access info on the operands being compared1137right_op_index = inst_right->operand_position(right_op, Component::USE);1138if( right_op_index == -1 ) {1139right_op_index = inst_right->operand_position(right_op, Component::DEF);1140if( right_op_index == -1 ) {1141right_op_index = inst_right->operand_position(right_op, Component::USE_DEF);1142}1143}1144assert( right_op_index != NameList::Not_in_list, "Did not find operand in instruction");1145ComponentList components_right = inst_right->_components;1146const char *right_comp_type = components_right.at(right_op_index)->_type;1147OpClassForm *right_opclass = globals[right_comp_type]->is_opclass();1148Form::InterfaceType right_interface_type = right_opclass->interface_type(globals);1149assert( right_interface_type == left_interface_type, "Both must be same interface");11501151} else { // Else match register1152// assert( false, "should be a register" );1153}11541155//1156// Check for equivalence1157//1158// fprintf(fp, "phase->eqv( ");1159// fprintf(fp, "inst%d->in(%d+%d) /* %s */, inst%d->in(%d+%d) /* %s */",1160// left_index, left_op_base, left_op_index, left_op,1161// right_index, right_op_base, right_op_index, right_op );1162// fprintf(fp, ")");1163//1164switch( left_interface_type ) {1165case Form::register_interface: {1166// Check that they are allocated to the same register1167// Need parameter for index position if not result operand1168char left_reg_index[] = ",instXXXX_idxXXXX";1169if( left_op_index != 0 ) {1170assert( (left_index <= 9999) && (left_op_index <= 9999), "exceed string size");1171// Must have index into operands1172sprintf(left_reg_index,",inst%d_idx%d", (int)left_index, left_op_index);1173} else {1174strcpy(left_reg_index, "");1175}1176fprintf(fp, "(inst%d->_opnds[%d]->reg(ra_,inst%d%s) /* %d.%s */",1177left_index, left_op_index, left_index, left_reg_index, left_index, left_op );1178fprintf(fp, " == ");11791180if( right_index != -1 ) {1181char right_reg_index[18] = ",instXXXX_idxXXXX";1182if( right_op_index != 0 ) {1183assert( (right_index <= 9999) && (right_op_index <= 9999), "exceed string size");1184// Must have index into operands1185sprintf(right_reg_index,",inst%d_idx%d", (int)right_index, right_op_index);1186} else {1187strcpy(right_reg_index, "");1188}1189fprintf(fp, "/* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)",1190right_index, right_op, right_index, right_op_index, right_index, right_reg_index );1191} else {1192fprintf(fp, "%s_enc", right_op );1193}1194fprintf(fp,")");1195break;1196}1197case Form::constant_interface: {1198// Compare the '->constant()' values1199fprintf(fp, "(inst%d->_opnds[%d]->constant() /* %d.%s */",1200left_index, left_op_index, left_index, left_op );1201fprintf(fp, " == ");1202fprintf(fp, "/* %d.%s */ inst%d->_opnds[%d]->constant())",1203right_index, right_op, right_index, right_op_index );1204break;1205}1206case Form::memory_interface: {1207// Compare 'base', 'index', 'scale', and 'disp'1208// base1209fprintf(fp, "( \n");1210fprintf(fp, " (inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d) /* %d.%s$$base */",1211left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );1212fprintf(fp, " == ");1213fprintf(fp, "/* %d.%s$$base */ inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d)) &&\n",1214right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );1215// index1216fprintf(fp, " (inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d) /* %d.%s$$index */",1217left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );1218fprintf(fp, " == ");1219fprintf(fp, "/* %d.%s$$index */ inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d)) &&\n",1220right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );1221// scale1222fprintf(fp, " (inst%d->_opnds[%d]->scale() /* %d.%s$$scale */",1223left_index, left_op_index, left_index, left_op );1224fprintf(fp, " == ");1225fprintf(fp, "/* %d.%s$$scale */ inst%d->_opnds[%d]->scale()) &&\n",1226right_index, right_op, right_index, right_op_index );1227// disp1228fprintf(fp, " (inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d) /* %d.%s$$disp */",1229left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );1230fprintf(fp, " == ");1231fprintf(fp, "/* %d.%s$$disp */ inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d))\n",1232right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );1233fprintf(fp, ") \n");1234break;1235}1236case Form::conditional_interface: {1237// Compare the condition code being tested1238assert( false, "Unimplemented()" );1239break;1240}1241default: {1242assert( false, "ShouldNotReachHere()" );1243break;1244}1245}12461247// Advance to next constraint1248pconstraint = pconstraint->next();1249first_constraint = false;1250}12511252fprintf(fp, ";\n");1253}1254}12551256// // EXPERIMENTAL -- TEMPORARY code1257// static Form::DataType get_operand_type(FormDict &globals, InstructForm *instr, const char *op_name ) {1258// int op_index = instr->operand_position(op_name, Component::USE);1259// if( op_index == -1 ) {1260// op_index = instr->operand_position(op_name, Component::DEF);1261// if( op_index == -1 ) {1262// op_index = instr->operand_position(op_name, Component::USE_DEF);1263// }1264// }1265// assert( op_index != NameList::Not_in_list, "Did not find operand in instruction");1266//1267// ComponentList components_right = instr->_components;1268// char *right_comp_type = components_right.at(op_index)->_type;1269// OpClassForm *right_opclass = globals[right_comp_type]->is_opclass();1270// Form::InterfaceType right_interface_type = right_opclass->interface_type(globals);1271//1272// return;1273// }12741275// Construct the new sub-tree1276static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch, PeepConstraint *pconstraint, PeepReplace *preplace, int max_position ) {1277fprintf(fp, " // IF instructions and constraints matched\n");1278fprintf(fp, " if( matches ) {\n");1279fprintf(fp, " // generate the new sub-tree\n");1280fprintf(fp, " assert( true, \"Debug stopping point\");\n");1281if( preplace != NULL ) {1282// Get the root of the new sub-tree1283const char *root_inst = NULL;1284preplace->next_instruction(root_inst);1285InstructForm *root_form = globals[root_inst]->is_instruction();1286assert( root_form != NULL, "Replacement instruction was not previously defined");1287fprintf(fp, " %sNode *root = new (C) %sNode();\n", root_inst, root_inst);12881289int inst_num;1290const char *op_name;1291int opnds_index = 0; // define result operand1292// Then install the use-operands for the new sub-tree1293// preplace->reset(); // reset breaks iteration1294for( preplace->next_operand( inst_num, op_name );1295op_name != NULL;1296preplace->next_operand( inst_num, op_name ) ) {1297InstructForm *inst_form;1298inst_form = globals[pmatch->instruction_name(inst_num)]->is_instruction();1299assert( inst_form, "Parser should guaranty this is an instruction");1300int inst_op_num = inst_form->operand_position(op_name, Component::USE);1301if( inst_op_num == NameList::Not_in_list )1302inst_op_num = inst_form->operand_position(op_name, Component::USE_DEF);1303assert( inst_op_num != NameList::Not_in_list, "Did not find operand as USE");1304// find the name of the OperandForm from the local name1305const Form *form = inst_form->_localNames[op_name];1306OperandForm *op_form = form->is_operand();1307if( opnds_index == 0 ) {1308// Initial setup of new instruction1309fprintf(fp, " // ----- Initial setup -----\n");1310//1311// Add control edge for this node1312fprintf(fp, " root->add_req(_in[0]); // control edge\n");1313// Add unmatched edges from root of match tree1314int op_base = root_form->oper_input_base(globals);1315for( int unmatched_edge = 1; unmatched_edge < op_base; ++unmatched_edge ) {1316fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",1317inst_num, unmatched_edge);1318}1319// If new instruction captures bottom type1320if( root_form->captures_bottom_type(globals) ) {1321// Get bottom type from instruction whose result we are replacing1322fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);1323}1324// Define result register and result operand1325fprintf(fp, " ra_->add_reference(root, inst%d);\n", inst_num);1326fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num);1327fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num);1328fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(C); // result\n", inst_num);1329fprintf(fp, " // ----- Done with initial setup -----\n");1330} else {1331if( (op_form == NULL) || (op_form->is_base_constant(globals) == Form::none) ) {1332// Do not have ideal edges for constants after matching1333fprintf(fp, " for( unsigned x%d = inst%d_idx%d; x%d < inst%d_idx%d; x%d++ )\n",1334inst_op_num, inst_num, inst_op_num,1335inst_op_num, inst_num, inst_op_num+1, inst_op_num );1336fprintf(fp, " root->add_req( inst%d->in(x%d) );\n",1337inst_num, inst_op_num );1338} else {1339fprintf(fp, " // no ideal edge for constants after matching\n");1340}1341fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone(C);\n",1342opnds_index, inst_num, inst_op_num );1343}1344++opnds_index;1345}1346}else {1347// Replacing subtree with empty-tree1348assert( false, "ShouldNotReachHere();");1349}13501351// Return the new sub-tree1352fprintf(fp, " deleted = %d;\n", max_position+1 /*zero to one based*/);1353fprintf(fp, " return root; // return new root;\n");1354fprintf(fp, " }\n");1355}135613571358// Define the Peephole method for an instruction node1359void ArchDesc::definePeephole(FILE *fp, InstructForm *node) {1360// Generate Peephole function header1361fprintf(fp, "MachNode *%sNode::peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ) {\n", node->_ident);1362fprintf(fp, " bool matches = true;\n");13631364// Identify the maximum instruction position,1365// generate temporaries that hold current instruction1366//1367// MachNode *inst0 = NULL;1368// ...1369// MachNode *instMAX = NULL;1370//1371int max_position = 0;1372Peephole *peep;1373for( peep = node->peepholes(); peep != NULL; peep = peep->next() ) {1374PeepMatch *pmatch = peep->match();1375assert( pmatch != NULL, "fatal(), missing peepmatch rule");1376if( max_position < pmatch->max_position() ) max_position = pmatch->max_position();1377}1378for( int i = 0; i <= max_position; ++i ) {1379if( i == 0 ) {1380fprintf(fp, " MachNode *inst0 = this;\n");1381} else {1382fprintf(fp, " MachNode *inst%d = NULL;\n", i);1383}1384}13851386// For each peephole rule in architecture description1387// Construct a test for the desired instruction sub-tree1388// then check the constraints1389// If these match, Generate the new subtree1390for( peep = node->peepholes(); peep != NULL; peep = peep->next() ) {1391int peephole_number = peep->peephole_number();1392PeepMatch *pmatch = peep->match();1393PeepConstraint *pconstraint = peep->constraints();1394PeepReplace *preplace = peep->replacement();13951396// Root of this peephole is the current MachNode1397assert( true, // %%name?%% strcmp( node->_ident, pmatch->name(0) ) == 0,1398"root of PeepMatch does not match instruction");13991400// Make each peephole rule individually selectable1401fprintf(fp, " if( (OptoPeepholeAt == -1) || (OptoPeepholeAt==%d) ) {\n", peephole_number);1402fprintf(fp, " matches = true;\n");1403// Scan the peepmatch and output a test for each instruction1404check_peepmatch_instruction_sequence( fp, pmatch, pconstraint );14051406// Check constraints and build replacement inside scope1407fprintf(fp, " // If instruction subtree matches\n");1408fprintf(fp, " if( matches ) {\n");14091410// Generate tests for the constraints1411check_peepconstraints( fp, _globalNames, pmatch, pconstraint );14121413// Construct the new sub-tree1414generate_peepreplace( fp, _globalNames, pmatch, pconstraint, preplace, max_position );14151416// End of scope for this peephole's constraints1417fprintf(fp, " }\n");1418// Closing brace '}' to make each peephole rule individually selectable1419fprintf(fp, " } // end of peephole rule #%d\n", peephole_number);1420fprintf(fp, "\n");1421}14221423fprintf(fp, " return NULL; // No peephole rules matched\n");1424fprintf(fp, "}\n");1425fprintf(fp, "\n");1426}14271428// Define the Expand method for an instruction node1429void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {1430unsigned cnt = 0; // Count nodes we have expand into1431unsigned i;14321433// Generate Expand function header1434fprintf(fp, "MachNode* %sNode::Expand(State* state, Node_List& proj_list, Node* mem) {\n", node->_ident);1435fprintf(fp, " Compile* C = Compile::current();\n");1436// Generate expand code1437if( node->expands() ) {1438const char *opid;1439int new_pos, exp_pos;1440const char *new_id = NULL;1441const Form *frm = NULL;1442InstructForm *new_inst = NULL;1443OperandForm *new_oper = NULL;1444unsigned numo = node->num_opnds() +1445node->_exprule->_newopers.count();14461447// If necessary, generate any operands created in expand rule1448if (node->_exprule->_newopers.count()) {1449for(node->_exprule->_newopers.reset();1450(new_id = node->_exprule->_newopers.iter()) != NULL; cnt++) {1451frm = node->_localNames[new_id];1452assert(frm, "Invalid entry in new operands list of expand rule");1453new_oper = frm->is_operand();1454char *tmp = (char *)node->_exprule->_newopconst[new_id];1455if (tmp == NULL) {1456fprintf(fp," MachOper *op%d = new (C) %sOper();\n",1457cnt, new_oper->_ident);1458}1459else {1460fprintf(fp," MachOper *op%d = new (C) %sOper(%s);\n",1461cnt, new_oper->_ident, tmp);1462}1463}1464}1465cnt = 0;1466// Generate the temps to use for DAG building1467for(i = 0; i < numo; i++) {1468if (i < node->num_opnds()) {1469fprintf(fp," MachNode *tmp%d = this;\n", i);1470}1471else {1472fprintf(fp," MachNode *tmp%d = NULL;\n", i);1473}1474}1475// Build mapping from num_edges to local variables1476fprintf(fp," unsigned num0 = 0;\n");1477for( i = 1; i < node->num_opnds(); i++ ) {1478fprintf(fp," unsigned num%d = opnd_array(%d)->num_edges();\n",i,i);1479}14801481// Build a mapping from operand index to input edges1482fprintf(fp," unsigned idx0 = oper_input_base();\n");14831484// The order in which the memory input is added to a node is very1485// strange. Store nodes get a memory input before Expand is1486// called and other nodes get it afterwards or before depending on1487// match order so oper_input_base is wrong during expansion. This1488// code adjusts it so that expansion will work correctly.1489int has_memory_edge = node->_matrule->needs_ideal_memory_edge(_globalNames);1490if (has_memory_edge) {1491fprintf(fp," if (mem == (Node*)1) {\n");1492fprintf(fp," idx0--; // Adjust base because memory edge hasn't been inserted yet\n");1493fprintf(fp," }\n");1494}14951496for( i = 0; i < node->num_opnds(); i++ ) {1497fprintf(fp," unsigned idx%d = idx%d + num%d;\n",1498i+1,i,i);1499}15001501// Declare variable to hold root of expansion1502fprintf(fp," MachNode *result = NULL;\n");15031504// Iterate over the instructions 'node' expands into1505ExpandRule *expand = node->_exprule;1506NameAndList *expand_instr = NULL;1507for(expand->reset_instructions();1508(expand_instr = expand->iter_instructions()) != NULL; cnt++) {1509new_id = expand_instr->name();15101511InstructForm* expand_instruction = (InstructForm*)globalAD->globalNames()[new_id];15121513if (!expand_instruction) {1514globalAD->syntax_err(node->_linenum, "In %s: instruction %s used in expand not declared\n",1515node->_ident, new_id);1516continue;1517}15181519if (expand_instruction->has_temps()) {1520globalAD->syntax_err(node->_linenum, "In %s: expand rules using instructs with TEMPs aren't supported: %s",1521node->_ident, new_id);1522}15231524// Build the node for the instruction1525fprintf(fp,"\n %sNode *n%d = new (C) %sNode();\n", new_id, cnt, new_id);1526// Add control edge for this node1527fprintf(fp," n%d->add_req(_in[0]);\n", cnt);1528// Build the operand for the value this node defines.1529Form *form = (Form*)_globalNames[new_id];1530assert( form, "'new_id' must be a defined form name");1531// Grab the InstructForm for the new instruction1532new_inst = form->is_instruction();1533assert( new_inst, "'new_id' must be an instruction name");1534if( node->is_ideal_if() && new_inst->is_ideal_if() ) {1535fprintf(fp, " ((MachIfNode*)n%d)->_prob = _prob;\n",cnt);1536fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n",cnt);1537}15381539if( node->is_ideal_fastlock() && new_inst->is_ideal_fastlock() ) {1540fprintf(fp, " ((MachFastLockNode*)n%d)->_counters = _counters;\n",cnt);1541fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n",cnt);1542fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n",cnt);1543}15441545// Fill in the bottom_type where requested1546if (node->captures_bottom_type(_globalNames) &&1547new_inst->captures_bottom_type(_globalNames)) {1548fprintf(fp, " ((MachTypeNode*)n%d)->_bottom_type = bottom_type();\n", cnt);1549}15501551const char *resultOper = new_inst->reduce_result();1552fprintf(fp," n%d->set_opnd_array(0, state->MachOperGenerator( %s, C ));\n",1553cnt, machOperEnum(resultOper));15541555// get the formal operand NameList1556NameList *formal_lst = &new_inst->_parameters;1557formal_lst->reset();15581559// Handle any memory operand1560int memory_operand = new_inst->memory_operand(_globalNames);1561if( memory_operand != InstructForm::NO_MEMORY_OPERAND ) {1562int node_mem_op = node->memory_operand(_globalNames);1563assert( node_mem_op != InstructForm::NO_MEMORY_OPERAND,1564"expand rule member needs memory but top-level inst doesn't have any" );1565if (has_memory_edge) {1566// Copy memory edge1567fprintf(fp," if (mem != (Node*)1) {\n");1568fprintf(fp," n%d->add_req(_in[1]);\t// Add memory edge\n", cnt);1569fprintf(fp," }\n");1570}1571}15721573// Iterate over the new instruction's operands1574int prev_pos = -1;1575for( expand_instr->reset(); (opid = expand_instr->iter()) != NULL; ) {1576// Use 'parameter' at current position in list of new instruction's formals1577// instead of 'opid' when looking up info internal to new_inst1578const char *parameter = formal_lst->iter();1579if (!parameter) {1580globalAD->syntax_err(node->_linenum, "Operand %s of expand instruction %s has"1581" no equivalent in new instruction %s.",1582opid, node->_ident, new_inst->_ident);1583assert(0, "Wrong expand");1584}15851586// Check for an operand which is created in the expand rule1587if ((exp_pos = node->_exprule->_newopers.index(opid)) != -1) {1588new_pos = new_inst->operand_position(parameter,Component::USE);1589exp_pos += node->num_opnds();1590// If there is no use of the created operand, just skip it1591if (new_pos != NameList::Not_in_list) {1592//Copy the operand from the original made above1593fprintf(fp," n%d->set_opnd_array(%d, op%d->clone(C)); // %s\n",1594cnt, new_pos, exp_pos-node->num_opnds(), opid);1595// Check for who defines this operand & add edge if needed1596fprintf(fp," if(tmp%d != NULL)\n", exp_pos);1597fprintf(fp," n%d->add_req(tmp%d);\n", cnt, exp_pos);1598}1599}1600else {1601// Use operand name to get an index into instruction component list1602// ins = (InstructForm *) _globalNames[new_id];1603exp_pos = node->operand_position_format(opid);1604assert(exp_pos != -1, "Bad expand rule");1605if (prev_pos > exp_pos && expand_instruction->_matrule != NULL) {1606// For the add_req calls below to work correctly they need1607// to added in the same order that a match would add them.1608// This means that they would need to be in the order of1609// the components list instead of the formal parameters.1610// This is a sort of hidden invariant that previously1611// wasn't checked and could lead to incorrectly1612// constructed nodes.1613syntax_err(node->_linenum, "For expand in %s to work, parameter declaration order in %s must follow matchrule\n",1614node->_ident, new_inst->_ident);1615}1616prev_pos = exp_pos;16171618new_pos = new_inst->operand_position(parameter,Component::USE);1619if (new_pos != -1) {1620// Copy the operand from the ExpandNode to the new node1621fprintf(fp," n%d->set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n",1622cnt, new_pos, exp_pos, opid);1623// For each operand add appropriate input edges by looking at tmp's1624fprintf(fp," if(tmp%d == this) {\n", exp_pos);1625// Grab corresponding edges from ExpandNode and insert them here1626fprintf(fp," for(unsigned i = 0; i < num%d; i++) {\n", exp_pos);1627fprintf(fp," n%d->add_req(_in[i + idx%d]);\n", cnt, exp_pos);1628fprintf(fp," }\n");1629fprintf(fp," }\n");1630// This value is generated by one of the new instructions1631fprintf(fp," else n%d->add_req(tmp%d);\n", cnt, exp_pos);1632}1633}16341635// Update the DAG tmp's for values defined by this instruction1636int new_def_pos = new_inst->operand_position(parameter,Component::DEF);1637Effect *eform = (Effect *)new_inst->_effects[parameter];1638// If this operand is a definition in either an effects rule1639// or a match rule1640if((eform) && (is_def(eform->_use_def))) {1641// Update the temp associated with this operand1642fprintf(fp," tmp%d = n%d;\n", exp_pos, cnt);1643}1644else if( new_def_pos != -1 ) {1645// Instruction defines a value but user did not declare it1646// in the 'effect' clause1647fprintf(fp," tmp%d = n%d;\n", exp_pos, cnt);1648}1649} // done iterating over a new instruction's operands16501651// Invoke Expand() for the newly created instruction.1652fprintf(fp," result = n%d->Expand( state, proj_list, mem );\n", cnt);1653assert( !new_inst->expands(), "Do not have complete support for recursive expansion");1654} // done iterating over new instructions1655fprintf(fp,"\n");1656} // done generating expand rule16571658// Generate projections for instruction's additional DEFs and KILLs1659if( ! node->expands() && (node->needs_projections() || node->has_temps())) {1660// Get string representing the MachNode that projections point at1661const char *machNode = "this";1662// Generate the projections1663fprintf(fp," // Add projection edges for additional defs or kills\n");16641665// Examine each component to see if it is a DEF or KILL1666node->_components.reset();1667// Skip the first component, if already handled as (SET dst (...))1668Component *comp = NULL;1669// For kills, the choice of projection numbers is arbitrary1670int proj_no = 1;1671bool declared_def = false;1672bool declared_kill = false;16731674while( (comp = node->_components.iter()) != NULL ) {1675// Lookup register class associated with operand type1676Form *form = (Form*)_globalNames[comp->_type];1677assert( form, "component type must be a defined form");1678OperandForm *op = form->is_operand();16791680if (comp->is(Component::TEMP)) {1681fprintf(fp, " // TEMP %s\n", comp->_name);1682if (!declared_def) {1683// Define the variable "def" to hold new MachProjNodes1684fprintf(fp, " MachTempNode *def;\n");1685declared_def = true;1686}1687if (op && op->_interface && op->_interface->is_RegInterface()) {1688fprintf(fp," def = new (C) MachTempNode(state->MachOperGenerator( %s, C ));\n",1689machOperEnum(op->_ident));1690fprintf(fp," add_req(def);\n");1691// The operand for TEMP is already constructed during1692// this mach node construction, see buildMachNode().1693//1694// int idx = node->operand_position_format(comp->_name);1695// fprintf(fp," set_opnd_array(%d, state->MachOperGenerator( %s, C ));\n",1696// idx, machOperEnum(op->_ident));1697} else {1698assert(false, "can't have temps which aren't registers");1699}1700} else if (comp->isa(Component::KILL)) {1701fprintf(fp, " // DEF/KILL %s\n", comp->_name);17021703if (!declared_kill) {1704// Define the variable "kill" to hold new MachProjNodes1705fprintf(fp, " MachProjNode *kill;\n");1706declared_kill = true;1707}17081709assert( op, "Support additional KILLS for base operands");1710const char *regmask = reg_mask(*op);1711const char *ideal_type = op->ideal_type(_globalNames, _register);17121713if (!op->is_bound_register()) {1714syntax_err(node->_linenum, "In %s only bound registers can be killed: %s %s\n",1715node->_ident, comp->_type, comp->_name);1716}17171718fprintf(fp," kill = ");1719fprintf(fp,"new (C) MachProjNode( %s, %d, (%s), Op_%s );\n",1720machNode, proj_no++, regmask, ideal_type);1721fprintf(fp," proj_list.push(kill);\n");1722}1723}1724}17251726if( !node->expands() && node->_matrule != NULL ) {1727// Remove duplicated operands and inputs which use the same name.1728// Seach through match operands for the same name usage.1729uint cur_num_opnds = node->num_opnds();1730if( cur_num_opnds > 1 && cur_num_opnds != node->num_unique_opnds() ) {1731Component *comp = NULL;1732// Build mapping from num_edges to local variables1733fprintf(fp," unsigned num0 = 0;\n");1734for( i = 1; i < cur_num_opnds; i++ ) {1735fprintf(fp," unsigned num%d = opnd_array(%d)->num_edges();",i,i);1736fprintf(fp, " \t// %s\n", node->opnd_ident(i));1737}1738// Build a mapping from operand index to input edges1739fprintf(fp," unsigned idx0 = oper_input_base();\n");1740for( i = 0; i < cur_num_opnds; i++ ) {1741fprintf(fp," unsigned idx%d = idx%d + num%d;\n",1742i+1,i,i);1743}17441745uint new_num_opnds = 1;1746node->_components.reset();1747// Skip first unique operands.1748for( i = 1; i < cur_num_opnds; i++ ) {1749comp = node->_components.iter();1750if (i != node->unique_opnds_idx(i)) {1751break;1752}1753new_num_opnds++;1754}1755// Replace not unique operands with next unique operands.1756for( ; i < cur_num_opnds; i++ ) {1757comp = node->_components.iter();1758uint j = node->unique_opnds_idx(i);1759// unique_opnds_idx(i) is unique if unique_opnds_idx(j) is not unique.1760if( j != node->unique_opnds_idx(j) ) {1761fprintf(fp," set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n",1762new_num_opnds, i, comp->_name);1763// delete not unique edges here1764fprintf(fp," for(unsigned i = 0; i < num%d; i++) {\n", i);1765fprintf(fp," set_req(i + idx%d, _in[i + idx%d]);\n", new_num_opnds, i);1766fprintf(fp," }\n");1767fprintf(fp," num%d = num%d;\n", new_num_opnds, i);1768fprintf(fp," idx%d = idx%d + num%d;\n", new_num_opnds+1, new_num_opnds, new_num_opnds);1769new_num_opnds++;1770}1771}1772// delete the rest of edges1773fprintf(fp," for(int i = idx%d - 1; i >= (int)idx%d; i--) {\n", cur_num_opnds, new_num_opnds);1774fprintf(fp," del_req(i);\n");1775fprintf(fp," }\n");1776fprintf(fp," _num_opnds = %d;\n", new_num_opnds);1777assert(new_num_opnds == node->num_unique_opnds(), "what?");1778}1779}17801781// If the node is a MachConstantNode, insert the MachConstantBaseNode edge.1782// NOTE: this edge must be the last input (see MachConstantNode::mach_constant_base_node_input).1783// There are nodes that don't use $constantablebase, but still require that it1784// is an input to the node. Example: divF_reg_immN, Repl32B_imm on x86_64.1785if (node->is_mach_constant() || node->needs_constant_base()) {1786if (node->is_ideal_call() != Form::invalid_type &&1787node->is_ideal_call() != Form::JAVA_LEAF) {1788fprintf(fp, " // MachConstantBaseNode added in matcher.\n");1789_needs_clone_jvms = true;1790} else {1791fprintf(fp, " add_req(C->mach_constant_base_node());\n");1792}1793}17941795fprintf(fp, "\n");1796if (node->expands()) {1797fprintf(fp, " return result;\n");1798} else {1799fprintf(fp, " return this;\n");1800}1801fprintf(fp, "}\n");1802fprintf(fp, "\n");1803}180418051806//------------------------------Emit Routines----------------------------------1807// Special classes and routines for defining node emit routines which output1808// target specific instruction object encodings.1809// Define the ___Node::emit() routine1810//1811// (1) void ___Node::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {1812// (2) // ... encoding defined by user1813// (3)1814// (4) }1815//18161817class DefineEmitState {1818private:1819enum reloc_format { RELOC_NONE = -1,1820RELOC_IMMEDIATE = 0,1821RELOC_DISP = 1,1822RELOC_CALL_DISP = 2 };1823enum literal_status{ LITERAL_NOT_SEEN = 0,1824LITERAL_SEEN = 1,1825LITERAL_ACCESSED = 2,1826LITERAL_OUTPUT = 3 };1827// Temporaries that describe current operand1828bool _cleared;1829OpClassForm *_opclass;1830OperandForm *_operand;1831int _operand_idx;1832const char *_local_name;1833const char *_operand_name;1834bool _doing_disp;1835bool _doing_constant;1836Form::DataType _constant_type;1837DefineEmitState::literal_status _constant_status;1838DefineEmitState::literal_status _reg_status;1839bool _doing_emit8;1840bool _doing_emit_d32;1841bool _doing_emit_d16;1842bool _doing_emit_hi;1843bool _doing_emit_lo;1844bool _may_reloc;1845reloc_format _reloc_form;1846const char * _reloc_type;1847bool _processing_noninput;18481849NameList _strings_to_emit;18501851// Stable state, set by constructor1852ArchDesc &_AD;1853FILE *_fp;1854EncClass &_encoding;1855InsEncode &_ins_encode;1856InstructForm &_inst;18571858public:1859DefineEmitState(FILE *fp, ArchDesc &AD, EncClass &encoding,1860InsEncode &ins_encode, InstructForm &inst)1861: _AD(AD), _fp(fp), _encoding(encoding), _ins_encode(ins_encode), _inst(inst) {1862clear();1863}18641865void clear() {1866_cleared = true;1867_opclass = NULL;1868_operand = NULL;1869_operand_idx = 0;1870_local_name = "";1871_operand_name = "";1872_doing_disp = false;1873_doing_constant= false;1874_constant_type = Form::none;1875_constant_status = LITERAL_NOT_SEEN;1876_reg_status = LITERAL_NOT_SEEN;1877_doing_emit8 = false;1878_doing_emit_d32= false;1879_doing_emit_d16= false;1880_doing_emit_hi = false;1881_doing_emit_lo = false;1882_may_reloc = false;1883_reloc_form = RELOC_NONE;1884_reloc_type = AdlcVMDeps::none_reloc_type();1885_strings_to_emit.clear();1886}18871888// Track necessary state when identifying a replacement variable1889// @arg rep_var: The formal parameter of the encoding.1890void update_state(const char *rep_var) {1891// A replacement variable or one of its subfields1892// Obtain replacement variable from list1893if ( (*rep_var) != '$' ) {1894// A replacement variable, '$' prefix1895// check_rep_var( rep_var );1896if ( Opcode::as_opcode_type(rep_var) != Opcode::NOT_AN_OPCODE ) {1897// No state needed.1898assert( _opclass == NULL,1899"'primary', 'secondary' and 'tertiary' don't follow operand.");1900}1901else if ((strcmp(rep_var, "constanttablebase") == 0) ||1902(strcmp(rep_var, "constantoffset") == 0) ||1903(strcmp(rep_var, "constantaddress") == 0)) {1904if (!(_inst.is_mach_constant() || _inst.needs_constant_base())) {1905_AD.syntax_err(_encoding._linenum,1906"Replacement variable %s not allowed in instruct %s (only in MachConstantNode or MachCall).\n",1907rep_var, _encoding._name);1908}1909}1910else {1911// Lookup its position in (formal) parameter list of encoding1912int param_no = _encoding.rep_var_index(rep_var);1913if ( param_no == -1 ) {1914_AD.syntax_err( _encoding._linenum,1915"Replacement variable %s not found in enc_class %s.\n",1916rep_var, _encoding._name);1917}19181919// Lookup the corresponding ins_encode parameter1920// This is the argument (actual parameter) to the encoding.1921const char *inst_rep_var = _ins_encode.rep_var_name(_inst, param_no);1922if (inst_rep_var == NULL) {1923_AD.syntax_err( _ins_encode._linenum,1924"Parameter %s not passed to enc_class %s from instruct %s.\n",1925rep_var, _encoding._name, _inst._ident);1926}19271928// Check if instruction's actual parameter is a local name in the instruction1929const Form *local = _inst._localNames[inst_rep_var];1930OpClassForm *opc = (local != NULL) ? local->is_opclass() : NULL;1931// Note: assert removed to allow constant and symbolic parameters1932// assert( opc, "replacement variable was not found in local names");1933// Lookup the index position iff the replacement variable is a localName1934int idx = (opc != NULL) ? _inst.operand_position_format(inst_rep_var) : -1;19351936if ( idx != -1 ) {1937// This is a local in the instruction1938// Update local state info.1939_opclass = opc;1940_operand_idx = idx;1941_local_name = rep_var;1942_operand_name = inst_rep_var;19431944// !!!!!1945// Do not support consecutive operands.1946assert( _operand == NULL, "Unimplemented()");1947_operand = opc->is_operand();1948}1949else if( ADLParser::is_literal_constant(inst_rep_var) ) {1950// Instruction provided a constant expression1951// Check later that encoding specifies $$$constant to resolve as constant1952_constant_status = LITERAL_SEEN;1953}1954else if( Opcode::as_opcode_type(inst_rep_var) != Opcode::NOT_AN_OPCODE ) {1955// Instruction provided an opcode: "primary", "secondary", "tertiary"1956// Check later that encoding specifies $$$constant to resolve as constant1957_constant_status = LITERAL_SEEN;1958}1959else if((_AD.get_registers() != NULL ) && (_AD.get_registers()->getRegDef(inst_rep_var) != NULL)) {1960// Instruction provided a literal register name for this parameter1961// Check that encoding specifies $$$reg to resolve.as register.1962_reg_status = LITERAL_SEEN;1963}1964else {1965// Check for unimplemented functionality before hard failure1966assert( strcmp(opc->_ident,"label")==0, "Unimplemented() Label");1967assert( false, "ShouldNotReachHere()");1968}1969} // done checking which operand this is.1970} else {1971//1972// A subfield variable, '$$' prefix1973// Check for fields that may require relocation information.1974// Then check that literal register parameters are accessed with 'reg' or 'constant'1975//1976if ( strcmp(rep_var,"$disp") == 0 ) {1977_doing_disp = true;1978assert( _opclass, "Must use operand or operand class before '$disp'");1979if( _operand == NULL ) {1980// Only have an operand class, generate run-time check for relocation1981_may_reloc = true;1982_reloc_form = RELOC_DISP;1983_reloc_type = AdlcVMDeps::oop_reloc_type();1984} else {1985// Do precise check on operand: is it a ConP or not1986//1987// Check interface for value of displacement1988assert( ( _operand->_interface != NULL ),1989"$disp can only follow memory interface operand");1990MemInterface *mem_interface= _operand->_interface->is_MemInterface();1991assert( mem_interface != NULL,1992"$disp can only follow memory interface operand");1993const char *disp = mem_interface->_disp;19941995if( disp != NULL && (*disp == '$') ) {1996// MemInterface::disp contains a replacement variable,1997// Check if this matches a ConP1998//1999// Lookup replacement variable, in operand's component list2000const char *rep_var_name = disp + 1; // Skip '$'2001const Component *comp = _operand->_components.search(rep_var_name);2002assert( comp != NULL,"Replacement variable not found in components");2003const char *type = comp->_type;2004// Lookup operand form for replacement variable's type2005const Form *form = _AD.globalNames()[type];2006assert( form != NULL, "Replacement variable's type not found");2007OperandForm *op = form->is_operand();2008assert( op, "Attempting to emit a non-register or non-constant");2009// Check if this is a constant2010if (op->_matrule && op->_matrule->is_base_constant(_AD.globalNames())) {2011// Check which constant this name maps to: _c0, _c1, ..., _cn2012// const int idx = _operand.constant_position(_AD.globalNames(), comp);2013// assert( idx != -1, "Constant component not found in operand");2014Form::DataType dtype = op->is_base_constant(_AD.globalNames());2015if ( dtype == Form::idealP ) {2016_may_reloc = true;2017// No longer true that idealP is always an oop2018_reloc_form = RELOC_DISP;2019_reloc_type = AdlcVMDeps::oop_reloc_type();2020}2021}20222023else if( _operand->is_user_name_for_sReg() != Form::none ) {2024// The only non-constant allowed access to disp is an operand sRegX in a stackSlotX2025assert( op->ideal_to_sReg_type(type) != Form::none, "StackSlots access displacements using 'sRegs'");2026_may_reloc = false;2027} else {2028assert( false, "fatal(); Only stackSlots can access a non-constant using 'disp'");2029}2030}2031} // finished with precise check of operand for relocation.2032} // finished with subfield variable2033else if ( strcmp(rep_var,"$constant") == 0 ) {2034_doing_constant = true;2035if ( _constant_status == LITERAL_NOT_SEEN ) {2036// Check operand for type of constant2037assert( _operand, "Must use operand before '$$constant'");2038Form::DataType dtype = _operand->is_base_constant(_AD.globalNames());2039_constant_type = dtype;2040if ( dtype == Form::idealP ) {2041_may_reloc = true;2042// No longer true that idealP is always an oop2043// // _must_reloc = true;2044_reloc_form = RELOC_IMMEDIATE;2045_reloc_type = AdlcVMDeps::oop_reloc_type();2046} else {2047// No relocation information needed2048}2049} else {2050// User-provided literals may not require relocation information !!!!!2051assert( _constant_status == LITERAL_SEEN, "Must know we are processing a user-provided literal");2052}2053}2054else if ( strcmp(rep_var,"$label") == 0 ) {2055// Calls containing labels require relocation2056if ( _inst.is_ideal_call() ) {2057_may_reloc = true;2058// !!!!! !!!!!2059_reloc_type = AdlcVMDeps::none_reloc_type();2060}2061}20622063// literal register parameter must be accessed as a 'reg' field.2064if ( _reg_status != LITERAL_NOT_SEEN ) {2065assert( _reg_status == LITERAL_SEEN, "Must have seen register literal before now");2066if (strcmp(rep_var,"$reg") == 0 || reg_conversion(rep_var) != NULL) {2067_reg_status = LITERAL_ACCESSED;2068} else {2069_AD.syntax_err(_encoding._linenum,2070"Invalid access to literal register parameter '%s' in %s.\n",2071rep_var, _encoding._name);2072assert( false, "invalid access to literal register parameter");2073}2074}2075// literal constant parameters must be accessed as a 'constant' field2076if (_constant_status != LITERAL_NOT_SEEN) {2077assert(_constant_status == LITERAL_SEEN, "Must have seen constant literal before now");2078if (strcmp(rep_var,"$constant") == 0) {2079_constant_status = LITERAL_ACCESSED;2080} else {2081_AD.syntax_err(_encoding._linenum,2082"Invalid access to literal constant parameter '%s' in %s.\n",2083rep_var, _encoding._name);2084}2085}2086} // end replacement and/or subfield20872088}20892090void add_rep_var(const char *rep_var) {2091// Handle subfield and replacement variables.2092if ( ( *rep_var == '$' ) && ( *(rep_var+1) == '$' ) ) {2093// Check for emit prefix, '$$emit32'2094assert( _cleared, "Can not nest $$$emit32");2095if ( strcmp(rep_var,"$$emit32") == 0 ) {2096_doing_emit_d32 = true;2097}2098else if ( strcmp(rep_var,"$$emit16") == 0 ) {2099_doing_emit_d16 = true;2100}2101else if ( strcmp(rep_var,"$$emit_hi") == 0 ) {2102_doing_emit_hi = true;2103}2104else if ( strcmp(rep_var,"$$emit_lo") == 0 ) {2105_doing_emit_lo = true;2106}2107else if ( strcmp(rep_var,"$$emit8") == 0 ) {2108_doing_emit8 = true;2109}2110else {2111_AD.syntax_err(_encoding._linenum, "Unsupported $$operation '%s'\n",rep_var);2112assert( false, "fatal();");2113}2114}2115else {2116// Update state for replacement variables2117update_state( rep_var );2118_strings_to_emit.addName(rep_var);2119}2120_cleared = false;2121}21222123void emit_replacement() {2124// A replacement variable or one of its subfields2125// Obtain replacement variable from list2126// const char *ec_rep_var = encoding->_rep_vars.iter();2127const char *rep_var;2128_strings_to_emit.reset();2129while ( (rep_var = _strings_to_emit.iter()) != NULL ) {21302131if ( (*rep_var) == '$' ) {2132// A subfield variable, '$$' prefix2133emit_field( rep_var );2134} else {2135if (_strings_to_emit.peek() != NULL &&2136strcmp(_strings_to_emit.peek(), "$Address") == 0) {2137fprintf(_fp, "Address::make_raw(");21382139emit_rep_var( rep_var );2140fprintf(_fp,"->base(ra_,this,idx%d), ", _operand_idx);21412142_reg_status = LITERAL_ACCESSED;2143emit_rep_var( rep_var );2144fprintf(_fp,"->index(ra_,this,idx%d), ", _operand_idx);21452146_reg_status = LITERAL_ACCESSED;2147emit_rep_var( rep_var );2148fprintf(_fp,"->scale(), ");21492150_reg_status = LITERAL_ACCESSED;2151emit_rep_var( rep_var );2152Form::DataType stack_type = _operand ? _operand->is_user_name_for_sReg() : Form::none;2153if( _operand && _operand_idx==0 && stack_type != Form::none ) {2154fprintf(_fp,"->disp(ra_,this,0), ");2155} else {2156fprintf(_fp,"->disp(ra_,this,idx%d), ", _operand_idx);2157}21582159_reg_status = LITERAL_ACCESSED;2160emit_rep_var( rep_var );2161fprintf(_fp,"->disp_reloc())");21622163// skip trailing $Address2164_strings_to_emit.iter();2165} else {2166// A replacement variable, '$' prefix2167const char* next = _strings_to_emit.peek();2168const char* next2 = _strings_to_emit.peek(2);2169if (next != NULL && next2 != NULL && strcmp(next2, "$Register") == 0 &&2170(strcmp(next, "$base") == 0 || strcmp(next, "$index") == 0)) {2171// handle $rev_var$$base$$Register and $rev_var$$index$$Register by2172// producing as_Register(opnd_array(#)->base(ra_,this,idx1)).2173fprintf(_fp, "as_Register(");2174// emit the operand reference2175emit_rep_var( rep_var );2176rep_var = _strings_to_emit.iter();2177assert(strcmp(rep_var, "$base") == 0 || strcmp(rep_var, "$index") == 0, "bad pattern");2178// handle base or index2179emit_field(rep_var);2180rep_var = _strings_to_emit.iter();2181assert(strcmp(rep_var, "$Register") == 0, "bad pattern");2182// close up the parens2183fprintf(_fp, ")");2184} else {2185emit_rep_var( rep_var );2186}2187}2188} // end replacement and/or subfield2189}2190}21912192void emit_reloc_type(const char* type) {2193fprintf(_fp, "%s", type)2194;2195}219621972198void emit() {2199//2200// "emit_d32_reloc(" or "emit_hi_reloc" or "emit_lo_reloc"2201//2202// Emit the function name when generating an emit function2203if ( _doing_emit_d32 || _doing_emit_hi || _doing_emit_lo ) {2204const char *d32_hi_lo = _doing_emit_d32 ? "d32" : (_doing_emit_hi ? "hi" : "lo");2205// In general, relocatable isn't known at compiler compile time.2206// Check results of prior scan2207if ( ! _may_reloc ) {2208// Definitely don't need relocation information2209fprintf( _fp, "emit_%s(cbuf, ", d32_hi_lo );2210emit_replacement(); fprintf(_fp, ")");2211}2212else {2213// Emit RUNTIME CHECK to see if value needs relocation info2214// If emitting a relocatable address, use 'emit_d32_reloc'2215const char *disp_constant = _doing_disp ? "disp" : _doing_constant ? "constant" : "INVALID";2216assert( (_doing_disp || _doing_constant)2217&& !(_doing_disp && _doing_constant),2218"Must be emitting either a displacement or a constant");2219fprintf(_fp,"\n");2220fprintf(_fp,"if ( opnd_array(%d)->%s_reloc() != relocInfo::none ) {\n",2221_operand_idx, disp_constant);2222fprintf(_fp," ");2223fprintf(_fp,"emit_%s_reloc(cbuf, ", d32_hi_lo );2224emit_replacement(); fprintf(_fp,", ");2225fprintf(_fp,"opnd_array(%d)->%s_reloc(), ",2226_operand_idx, disp_constant);2227fprintf(_fp, "%d", _reloc_form);fprintf(_fp, ");");2228fprintf(_fp,"\n");2229fprintf(_fp,"} else {\n");2230fprintf(_fp," emit_%s(cbuf, ", d32_hi_lo);2231emit_replacement(); fprintf(_fp, ");\n"); fprintf(_fp,"}");2232}2233}2234else if ( _doing_emit_d16 ) {2235// Relocation of 16-bit values is not supported2236fprintf(_fp,"emit_d16(cbuf, ");2237emit_replacement(); fprintf(_fp, ")");2238// No relocation done for 16-bit values2239}2240else if ( _doing_emit8 ) {2241// Relocation of 8-bit values is not supported2242fprintf(_fp,"emit_d8(cbuf, ");2243emit_replacement(); fprintf(_fp, ")");2244// No relocation done for 8-bit values2245}2246else {2247// Not an emit# command, just output the replacement string.2248emit_replacement();2249}22502251// Get ready for next state collection.2252clear();2253}22542255private:22562257// recognizes names which represent MacroAssembler register types2258// and return the conversion function to build them from OptoReg2259const char* reg_conversion(const char* rep_var) {2260if (strcmp(rep_var,"$Register") == 0) return "as_Register";2261if (strcmp(rep_var,"$FloatRegister") == 0) return "as_FloatRegister";2262#if defined(IA32) || defined(AMD64)2263if (strcmp(rep_var,"$XMMRegister") == 0) return "as_XMMRegister";2264#endif2265if (strcmp(rep_var,"$CondRegister") == 0) return "as_ConditionRegister";2266return NULL;2267}22682269void emit_field(const char *rep_var) {2270const char* reg_convert = reg_conversion(rep_var);22712272// A subfield variable, '$$subfield'2273if ( strcmp(rep_var, "$reg") == 0 || reg_convert != NULL) {2274// $reg form or the $Register MacroAssembler type conversions2275assert( _operand_idx != -1,2276"Must use this subfield after operand");2277if( _reg_status == LITERAL_NOT_SEEN ) {2278if (_processing_noninput) {2279const Form *local = _inst._localNames[_operand_name];2280OperandForm *oper = local->is_operand();2281const RegDef* first = oper->get_RegClass()->find_first_elem();2282if (reg_convert != NULL) {2283fprintf(_fp, "%s(%s_enc)", reg_convert, first->_regname);2284} else {2285fprintf(_fp, "%s_enc", first->_regname);2286}2287} else {2288fprintf(_fp,"->%s(ra_,this", reg_convert != NULL ? reg_convert : "reg");2289// Add parameter for index position, if not result operand2290if( _operand_idx != 0 ) fprintf(_fp,",idx%d", _operand_idx);2291fprintf(_fp,")");2292fprintf(_fp, "/* %s */", _operand_name);2293}2294} else {2295assert( _reg_status == LITERAL_OUTPUT, "should have output register literal in emit_rep_var");2296// Register literal has already been sent to output file, nothing more needed2297}2298}2299else if ( strcmp(rep_var,"$base") == 0 ) {2300assert( _operand_idx != -1,2301"Must use this subfield after operand");2302assert( ! _may_reloc, "UnImplemented()");2303fprintf(_fp,"->base(ra_,this,idx%d)", _operand_idx);2304}2305else if ( strcmp(rep_var,"$index") == 0 ) {2306assert( _operand_idx != -1,2307"Must use this subfield after operand");2308assert( ! _may_reloc, "UnImplemented()");2309fprintf(_fp,"->index(ra_,this,idx%d)", _operand_idx);2310}2311else if ( strcmp(rep_var,"$scale") == 0 ) {2312assert( ! _may_reloc, "UnImplemented()");2313fprintf(_fp,"->scale()");2314}2315else if ( strcmp(rep_var,"$cmpcode") == 0 ) {2316assert( ! _may_reloc, "UnImplemented()");2317fprintf(_fp,"->ccode()");2318}2319else if ( strcmp(rep_var,"$constant") == 0 ) {2320if( _constant_status == LITERAL_NOT_SEEN ) {2321if ( _constant_type == Form::idealD ) {2322fprintf(_fp,"->constantD()");2323} else if ( _constant_type == Form::idealF ) {2324fprintf(_fp,"->constantF()");2325} else if ( _constant_type == Form::idealL ) {2326fprintf(_fp,"->constantL()");2327} else {2328fprintf(_fp,"->constant()");2329}2330} else {2331assert( _constant_status == LITERAL_OUTPUT, "should have output constant literal in emit_rep_var");2332// Constant literal has already been sent to output file, nothing more needed2333}2334}2335else if ( strcmp(rep_var,"$disp") == 0 ) {2336Form::DataType stack_type = _operand ? _operand->is_user_name_for_sReg() : Form::none;2337if( _operand && _operand_idx==0 && stack_type != Form::none ) {2338fprintf(_fp,"->disp(ra_,this,0)");2339} else {2340fprintf(_fp,"->disp(ra_,this,idx%d)", _operand_idx);2341}2342}2343else if ( strcmp(rep_var,"$label") == 0 ) {2344fprintf(_fp,"->label()");2345}2346else if ( strcmp(rep_var,"$method") == 0 ) {2347fprintf(_fp,"->method()");2348}2349else {2350printf("emit_field: %s\n",rep_var);2351globalAD->syntax_err(_inst._linenum, "Unknown replacement variable %s in format statement of %s.",2352rep_var, _inst._ident);2353assert( false, "UnImplemented()");2354}2355}235623572358void emit_rep_var(const char *rep_var) {2359_processing_noninput = false;2360// A replacement variable, originally '$'2361if ( Opcode::as_opcode_type(rep_var) != Opcode::NOT_AN_OPCODE ) {2362if (!_inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(rep_var) )) {2363// Missing opcode2364_AD.syntax_err( _inst._linenum,2365"Missing $%s opcode definition in %s, used by encoding %s\n",2366rep_var, _inst._ident, _encoding._name);2367}2368}2369else if (strcmp(rep_var, "constanttablebase") == 0) {2370fprintf(_fp, "as_Register(ra_->get_encode(in(mach_constant_base_node_input())))");2371}2372else if (strcmp(rep_var, "constantoffset") == 0) {2373fprintf(_fp, "constant_offset()");2374}2375else if (strcmp(rep_var, "constantaddress") == 0) {2376fprintf(_fp, "InternalAddress(__ code()->consts()->start() + constant_offset())");2377}2378else {2379// Lookup its position in parameter list2380int param_no = _encoding.rep_var_index(rep_var);2381if ( param_no == -1 ) {2382_AD.syntax_err( _encoding._linenum,2383"Replacement variable %s not found in enc_class %s.\n",2384rep_var, _encoding._name);2385}2386// Lookup the corresponding ins_encode parameter2387const char *inst_rep_var = _ins_encode.rep_var_name(_inst, param_no);23882389// Check if instruction's actual parameter is a local name in the instruction2390const Form *local = _inst._localNames[inst_rep_var];2391OpClassForm *opc = (local != NULL) ? local->is_opclass() : NULL;2392// Note: assert removed to allow constant and symbolic parameters2393// assert( opc, "replacement variable was not found in local names");2394// Lookup the index position iff the replacement variable is a localName2395int idx = (opc != NULL) ? _inst.operand_position_format(inst_rep_var) : -1;2396if( idx != -1 ) {2397if (_inst.is_noninput_operand(idx)) {2398// This operand isn't a normal input so printing it is done2399// specially.2400_processing_noninput = true;2401} else {2402// Output the emit code for this operand2403fprintf(_fp,"opnd_array(%d)",idx);2404}2405assert( _operand == opc->is_operand(),2406"Previous emit $operand does not match current");2407}2408else if( ADLParser::is_literal_constant(inst_rep_var) ) {2409// else check if it is a constant expression2410// Removed following assert to allow primitive C types as arguments to encodings2411// assert( _constant_status == LITERAL_ACCESSED, "Must be processing a literal constant parameter");2412fprintf(_fp,"(%s)", inst_rep_var);2413_constant_status = LITERAL_OUTPUT;2414}2415else if( Opcode::as_opcode_type(inst_rep_var) != Opcode::NOT_AN_OPCODE ) {2416// else check if "primary", "secondary", "tertiary"2417assert( _constant_status == LITERAL_ACCESSED, "Must be processing a literal constant parameter");2418if (!_inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(inst_rep_var) )) {2419// Missing opcode2420_AD.syntax_err( _inst._linenum,2421"Missing $%s opcode definition in %s\n",2422rep_var, _inst._ident);24232424}2425_constant_status = LITERAL_OUTPUT;2426}2427else if((_AD.get_registers() != NULL ) && (_AD.get_registers()->getRegDef(inst_rep_var) != NULL)) {2428// Instruction provided a literal register name for this parameter2429// Check that encoding specifies $$$reg to resolve.as register.2430assert( _reg_status == LITERAL_ACCESSED, "Must be processing a literal register parameter");2431fprintf(_fp,"(%s_enc)", inst_rep_var);2432_reg_status = LITERAL_OUTPUT;2433}2434else {2435// Check for unimplemented functionality before hard failure2436assert( strcmp(opc->_ident,"label")==0, "Unimplemented() Label");2437assert( false, "ShouldNotReachHere()");2438}2439// all done2440}2441}24422443}; // end class DefineEmitState244424452446void ArchDesc::defineSize(FILE *fp, InstructForm &inst) {24472448//(1)2449// Output instruction's emit prototype2450fprintf(fp,"uint %sNode::size(PhaseRegAlloc *ra_) const {\n",2451inst._ident);24522453fprintf(fp, " assert(VerifyOops || MachNode::size(ra_) <= %s, \"bad fixed size\");\n", inst._size);24542455//(2)2456// Print the size2457fprintf(fp, " return (VerifyOops ? MachNode::size(ra_) : %s);\n", inst._size);24582459// (3) and (4)2460fprintf(fp,"}\n\n");2461}24622463// Emit postalloc expand function.2464void ArchDesc::define_postalloc_expand(FILE *fp, InstructForm &inst) {2465InsEncode *ins_encode = inst._insencode;24662467// Output instruction's postalloc_expand prototype.2468fprintf(fp, "void %sNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {\n",2469inst._ident);24702471assert((_encode != NULL) && (ins_encode != NULL), "You must define an encode section.");24722473// Output each operand's offset into the array of registers.2474inst.index_temps(fp, _globalNames);24752476// Output variables "unsigned idx_<par_name>", Node *n_<par_name> and "MachOpnd *op_<par_name>"2477// for each parameter <par_name> specified in the encoding.2478ins_encode->reset();2479const char *ec_name = ins_encode->encode_class_iter();2480assert(ec_name != NULL, "Postalloc expand must specify an encoding.");24812482EncClass *encoding = _encode->encClass(ec_name);2483if (encoding == NULL) {2484fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);2485abort();2486}2487if (ins_encode->current_encoding_num_args() != encoding->num_args()) {2488globalAD->syntax_err(ins_encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",2489inst._ident, ins_encode->current_encoding_num_args(),2490ec_name, encoding->num_args());2491}24922493fprintf(fp, " // Access to ins and operands for postalloc expand.\n");2494const int buflen = 2000;2495char idxbuf[buflen]; char *ib = idxbuf; idxbuf[0] = '\0';2496char nbuf [buflen]; char *nb = nbuf; nbuf[0] = '\0';2497char opbuf [buflen]; char *ob = opbuf; opbuf[0] = '\0';24982499encoding->_parameter_type.reset();2500encoding->_parameter_name.reset();2501const char *type = encoding->_parameter_type.iter();2502const char *name = encoding->_parameter_name.iter();2503int param_no = 0;2504for (; (type != NULL) && (name != NULL);2505(type = encoding->_parameter_type.iter()), (name = encoding->_parameter_name.iter())) {2506const char* arg_name = ins_encode->rep_var_name(inst, param_no);2507int idx = inst.operand_position_format(arg_name);2508if (strcmp(arg_name, "constanttablebase") == 0) {2509ib += sprintf(ib, " unsigned idx_%-5s = mach_constant_base_node_input(); \t// %s, \t%s\n",2510name, type, arg_name);2511nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);2512// There is no operand for the constanttablebase.2513} else if (inst.is_noninput_operand(idx)) {2514globalAD->syntax_err(inst._linenum,2515"In %s: you can not pass the non-input %s to a postalloc expand encoding.\n",2516inst._ident, arg_name);2517} else {2518ib += sprintf(ib, " unsigned idx_%-5s = idx%d; \t// %s, \t%s\n",2519name, idx, type, arg_name);2520nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);2521ob += sprintf(ob, " %sOper *op_%s = (%sOper *)opnd_array(%d);\n", type, name, type, idx);2522}2523param_no++;2524}2525assert(ib < &idxbuf[buflen-1] && nb < &nbuf[buflen-1] && ob < &opbuf[buflen-1], "buffer overflow");25262527fprintf(fp, "%s", idxbuf);2528fprintf(fp, " Node *n_region = lookup(0);\n");2529fprintf(fp, "%s%s", nbuf, opbuf);2530fprintf(fp, " Compile *C = ra_->C;\n");25312532// Output this instruction's encodings.2533fprintf(fp, " {");2534const char *ec_code = NULL;2535const char *ec_rep_var = NULL;2536assert(encoding == _encode->encClass(ec_name), "");25372538DefineEmitState pending(fp, *this, *encoding, *ins_encode, inst);2539encoding->_code.reset();2540encoding->_rep_vars.reset();2541// Process list of user-defined strings,2542// and occurrences of replacement variables.2543// Replacement Vars are pushed into a list and then output.2544while ((ec_code = encoding->_code.iter()) != NULL) {2545if (! encoding->_code.is_signal(ec_code)) {2546// Emit pending code.2547pending.emit();2548pending.clear();2549// Emit this code section.2550fprintf(fp, "%s", ec_code);2551} else {2552// A replacement variable or one of its subfields.2553// Obtain replacement variable from list.2554ec_rep_var = encoding->_rep_vars.iter();2555pending.add_rep_var(ec_rep_var);2556}2557}2558// Emit pending code.2559pending.emit();2560pending.clear();2561fprintf(fp, " }\n");25622563fprintf(fp, "}\n\n");25642565ec_name = ins_encode->encode_class_iter();2566assert(ec_name == NULL, "Postalloc expand may only have one encoding.");2567}25682569// defineEmit -----------------------------------------------------------------2570void ArchDesc::defineEmit(FILE* fp, InstructForm& inst) {2571InsEncode* encode = inst._insencode;25722573// (1)2574// Output instruction's emit prototype2575fprintf(fp, "void %sNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {\n", inst._ident);25762577// If user did not define an encode section,2578// provide stub that does not generate any machine code.2579if( (_encode == NULL) || (encode == NULL) ) {2580fprintf(fp, " // User did not define an encode section.\n");2581fprintf(fp, "}\n");2582return;2583}25842585// Save current instruction's starting address (helps with relocation).2586fprintf(fp, " cbuf.set_insts_mark();\n");25872588// For MachConstantNodes which are ideal jump nodes, fill the jump table.2589if (inst.is_mach_constant() && inst.is_ideal_jump()) {2590fprintf(fp, " ra_->C->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");2591}25922593// Output each operand's offset into the array of registers.2594inst.index_temps(fp, _globalNames);25952596// Output this instruction's encodings2597const char *ec_name;2598bool user_defined = false;2599encode->reset();2600while ((ec_name = encode->encode_class_iter()) != NULL) {2601fprintf(fp, " {\n");2602// Output user-defined encoding2603user_defined = true;26042605const char *ec_code = NULL;2606const char *ec_rep_var = NULL;2607EncClass *encoding = _encode->encClass(ec_name);2608if (encoding == NULL) {2609fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);2610abort();2611}26122613if (encode->current_encoding_num_args() != encoding->num_args()) {2614globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",2615inst._ident, encode->current_encoding_num_args(),2616ec_name, encoding->num_args());2617}26182619DefineEmitState pending(fp, *this, *encoding, *encode, inst);2620encoding->_code.reset();2621encoding->_rep_vars.reset();2622// Process list of user-defined strings,2623// and occurrences of replacement variables.2624// Replacement Vars are pushed into a list and then output2625while ((ec_code = encoding->_code.iter()) != NULL) {2626if (!encoding->_code.is_signal(ec_code)) {2627// Emit pending code2628pending.emit();2629pending.clear();2630// Emit this code section2631fprintf(fp, "%s", ec_code);2632} else {2633// A replacement variable or one of its subfields2634// Obtain replacement variable from list2635ec_rep_var = encoding->_rep_vars.iter();2636pending.add_rep_var(ec_rep_var);2637}2638}2639// Emit pending code2640pending.emit();2641pending.clear();2642fprintf(fp, " }\n");2643} // end while instruction's encodings26442645// Check if user stated which encoding to user2646if ( user_defined == false ) {2647fprintf(fp, " // User did not define which encode class to use.\n");2648}26492650// (3) and (4)2651fprintf(fp, "}\n\n");2652}26532654// defineEvalConstant ---------------------------------------------------------2655void ArchDesc::defineEvalConstant(FILE* fp, InstructForm& inst) {2656InsEncode* encode = inst._constant;26572658// (1)2659// Output instruction's emit prototype2660fprintf(fp, "void %sNode::eval_constant(Compile* C) {\n", inst._ident);26612662// For ideal jump nodes, add a jump-table entry.2663if (inst.is_ideal_jump()) {2664fprintf(fp, " _constant = C->constant_table().add_jump_table(this);\n");2665}26662667// If user did not define an encode section,2668// provide stub that does not generate any machine code.2669if ((_encode == NULL) || (encode == NULL)) {2670fprintf(fp, " // User did not define an encode section.\n");2671fprintf(fp, "}\n");2672return;2673}26742675// Output this instruction's encodings2676const char *ec_name;2677bool user_defined = false;2678encode->reset();2679while ((ec_name = encode->encode_class_iter()) != NULL) {2680fprintf(fp, " {\n");2681// Output user-defined encoding2682user_defined = true;26832684const char *ec_code = NULL;2685const char *ec_rep_var = NULL;2686EncClass *encoding = _encode->encClass(ec_name);2687if (encoding == NULL) {2688fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);2689abort();2690}26912692if (encode->current_encoding_num_args() != encoding->num_args()) {2693globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",2694inst._ident, encode->current_encoding_num_args(),2695ec_name, encoding->num_args());2696}26972698DefineEmitState pending(fp, *this, *encoding, *encode, inst);2699encoding->_code.reset();2700encoding->_rep_vars.reset();2701// Process list of user-defined strings,2702// and occurrences of replacement variables.2703// Replacement Vars are pushed into a list and then output2704while ((ec_code = encoding->_code.iter()) != NULL) {2705if (!encoding->_code.is_signal(ec_code)) {2706// Emit pending code2707pending.emit();2708pending.clear();2709// Emit this code section2710fprintf(fp, "%s", ec_code);2711} else {2712// A replacement variable or one of its subfields2713// Obtain replacement variable from list2714ec_rep_var = encoding->_rep_vars.iter();2715pending.add_rep_var(ec_rep_var);2716}2717}2718// Emit pending code2719pending.emit();2720pending.clear();2721fprintf(fp, " }\n");2722} // end while instruction's encodings27232724// Check if user stated which encoding to user2725if (user_defined == false) {2726fprintf(fp, " // User did not define which encode class to use.\n");2727}27282729// (3) and (4)2730fprintf(fp, "}\n");2731}27322733// ---------------------------------------------------------------------------2734//--------Utilities to build MachOper and MachNode derived Classes------------2735// ---------------------------------------------------------------------------27362737//------------------------------Utilities to build Operand Classes------------2738static void defineIn_RegMask(FILE *fp, FormDict &globals, OperandForm &oper) {2739uint num_edges = oper.num_edges(globals);2740if( num_edges != 0 ) {2741// Method header2742fprintf(fp, "const RegMask *%sOper::in_RegMask(int index) const {\n",2743oper._ident);27442745// Assert that the index is in range.2746fprintf(fp, " assert(0 <= index && index < %d, \"index out of range\");\n",2747num_edges);27482749// Figure out if all RegMasks are the same.2750const char* first_reg_class = oper.in_reg_class(0, globals);2751bool all_same = true;2752assert(first_reg_class != NULL, "did not find register mask");27532754for (uint index = 1; all_same && index < num_edges; index++) {2755const char* some_reg_class = oper.in_reg_class(index, globals);2756assert(some_reg_class != NULL, "did not find register mask");2757if (strcmp(first_reg_class, some_reg_class) != 0) {2758all_same = false;2759}2760}27612762if (all_same) {2763// Return the sole RegMask.2764if (strcmp(first_reg_class, "stack_slots") == 0) {2765fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n");2766} else {2767const char* first_reg_class_to_upper = toUpper(first_reg_class);2768fprintf(fp," return &%s_mask();\n", first_reg_class_to_upper);2769delete[] first_reg_class_to_upper;2770}2771} else {2772// Build a switch statement to return the desired mask.2773fprintf(fp," switch (index) {\n");27742775for (uint index = 0; index < num_edges; index++) {2776const char *reg_class = oper.in_reg_class(index, globals);2777assert(reg_class != NULL, "did not find register mask");2778if( !strcmp(reg_class, "stack_slots") ) {2779fprintf(fp, " case %d: return &(Compile::current()->FIRST_STACK_mask());\n", index);2780} else {2781const char* reg_class_to_upper = toUpper(reg_class);2782fprintf(fp, " case %d: return &%s_mask();\n", index, reg_class_to_upper);2783delete[] reg_class_to_upper;2784}2785}2786fprintf(fp," }\n");2787fprintf(fp," ShouldNotReachHere();\n");2788fprintf(fp," return NULL;\n");2789}27902791// Method close2792fprintf(fp, "}\n\n");2793}2794}27952796// generate code to create a clone for a class derived from MachOper2797//2798// (0) MachOper *MachOperXOper::clone(Compile* C) const {2799// (1) return new (C) MachXOper( _ccode, _c0, _c1, ..., _cn);2800// (2) }2801//2802static void defineClone(FILE *fp, FormDict &globalNames, OperandForm &oper) {2803fprintf(fp,"MachOper *%sOper::clone(Compile* C) const {\n", oper._ident);2804// Check for constants that need to be copied over2805const int num_consts = oper.num_consts(globalNames);2806const bool is_ideal_bool = oper.is_ideal_bool();2807if( (num_consts > 0) ) {2808fprintf(fp," return new (C) %sOper(", oper._ident);2809// generate parameters for constants2810int i = 0;2811fprintf(fp,"_c%d", i);2812for( i = 1; i < num_consts; ++i) {2813fprintf(fp,", _c%d", i);2814}2815// finish line (1)2816fprintf(fp,");\n");2817}2818else {2819assert( num_consts == 0, "Currently support zero or one constant per operand clone function");2820fprintf(fp," return new (C) %sOper();\n", oper._ident);2821}2822// finish method2823fprintf(fp,"}\n");2824}28252826// Helper functions for bug 4796752, abstracted with minimal modification2827// from define_oper_interface()2828OperandForm *rep_var_to_operand(const char *encoding, OperandForm &oper, FormDict &globals) {2829OperandForm *op = NULL;2830// Check for replacement variable2831if( *encoding == '$' ) {2832// Replacement variable2833const char *rep_var = encoding + 1;2834// Lookup replacement variable, rep_var, in operand's component list2835const Component *comp = oper._components.search(rep_var);2836assert( comp != NULL, "Replacement variable not found in components");2837// Lookup operand form for replacement variable's type2838const char *type = comp->_type;2839Form *form = (Form*)globals[type];2840assert( form != NULL, "Replacement variable's type not found");2841op = form->is_operand();2842assert( op, "Attempting to emit a non-register or non-constant");2843}28442845return op;2846}28472848int rep_var_to_constant_index(const char *encoding, OperandForm &oper, FormDict &globals) {2849int idx = -1;2850// Check for replacement variable2851if( *encoding == '$' ) {2852// Replacement variable2853const char *rep_var = encoding + 1;2854// Lookup replacement variable, rep_var, in operand's component list2855const Component *comp = oper._components.search(rep_var);2856assert( comp != NULL, "Replacement variable not found in components");2857// Lookup operand form for replacement variable's type2858const char *type = comp->_type;2859Form *form = (Form*)globals[type];2860assert( form != NULL, "Replacement variable's type not found");2861OperandForm *op = form->is_operand();2862assert( op, "Attempting to emit a non-register or non-constant");2863// Check that this is a constant and find constant's index:2864if (op->_matrule && op->_matrule->is_base_constant(globals)) {2865idx = oper.constant_position(globals, comp);2866}2867}28682869return idx;2870}28712872bool is_regI(const char *encoding, OperandForm &oper, FormDict &globals ) {2873bool is_regI = false;28742875OperandForm *op = rep_var_to_operand(encoding, oper, globals);2876if( op != NULL ) {2877// Check that this is a register2878if ( (op->_matrule && op->_matrule->is_base_register(globals)) ) {2879// Register2880const char* ideal = op->ideal_type(globals);2881is_regI = (ideal && (op->ideal_to_Reg_type(ideal) == Form::idealI));2882}2883}28842885return is_regI;2886}28872888bool is_conP(const char *encoding, OperandForm &oper, FormDict &globals ) {2889bool is_conP = false;28902891OperandForm *op = rep_var_to_operand(encoding, oper, globals);2892if( op != NULL ) {2893// Check that this is a constant pointer2894if (op->_matrule && op->_matrule->is_base_constant(globals)) {2895// Constant2896Form::DataType dtype = op->is_base_constant(globals);2897is_conP = (dtype == Form::idealP);2898}2899}29002901return is_conP;2902}290329042905// Define a MachOper interface methods2906void ArchDesc::define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,2907const char *name, const char *encoding) {2908bool emit_position = false;2909int position = -1;29102911fprintf(fp," virtual int %s", name);2912// Generate access method for base, index, scale, disp, ...2913if( (strcmp(name,"base") == 0) || (strcmp(name,"index") == 0) ) {2914fprintf(fp,"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");2915emit_position = true;2916} else if ( (strcmp(name,"disp") == 0) ) {2917fprintf(fp,"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");2918} else {2919fprintf(fp, "() const {\n");2920}29212922// Check for hexadecimal value OR replacement variable2923if( *encoding == '$' ) {2924// Replacement variable2925const char *rep_var = encoding + 1;2926fprintf(fp," // Replacement variable: %s\n", encoding+1);2927// Lookup replacement variable, rep_var, in operand's component list2928const Component *comp = oper._components.search(rep_var);2929assert( comp != NULL, "Replacement variable not found in components");2930// Lookup operand form for replacement variable's type2931const char *type = comp->_type;2932Form *form = (Form*)globals[type];2933assert( form != NULL, "Replacement variable's type not found");2934OperandForm *op = form->is_operand();2935assert( op, "Attempting to emit a non-register or non-constant");2936// Check that this is a register or a constant and generate code:2937if ( (op->_matrule && op->_matrule->is_base_register(globals)) ) {2938// Register2939int idx_offset = oper.register_position( globals, rep_var);2940position = idx_offset;2941fprintf(fp," return (int)ra_->get_encode(node->in(idx");2942if ( idx_offset > 0 ) fprintf(fp, "+%d",idx_offset);2943fprintf(fp,"));\n");2944} else if ( op->ideal_to_sReg_type(op->_ident) != Form::none ) {2945// StackSlot for an sReg comes either from input node or from self, when idx==02946fprintf(fp," if( idx != 0 ) {\n");2947fprintf(fp," // Access stack offset (register number) for input operand\n");2948fprintf(fp," return ra_->reg2offset(ra_->get_reg_first(node->in(idx)));/* sReg */\n");2949fprintf(fp," }\n");2950fprintf(fp," // Access stack offset (register number) from myself\n");2951fprintf(fp," return ra_->reg2offset(ra_->get_reg_first(node));/* sReg */\n");2952} else if (op->_matrule && op->_matrule->is_base_constant(globals)) {2953// Constant2954// Check which constant this name maps to: _c0, _c1, ..., _cn2955const int idx = oper.constant_position(globals, comp);2956assert( idx != -1, "Constant component not found in operand");2957// Output code for this constant, type dependent.2958fprintf(fp," return (int)" );2959oper.access_constant(fp, globals, (uint)idx /* , const_type */);2960fprintf(fp,";\n");2961} else {2962assert( false, "Attempting to emit a non-register or non-constant");2963}2964}2965else if( *encoding == '0' && *(encoding+1) == 'x' ) {2966// Hex value2967fprintf(fp," return %s;\n", encoding);2968} else {2969globalAD->syntax_err(oper._linenum, "In operand %s: Do not support this encode constant: '%s' for %s.",2970oper._ident, encoding, name);2971assert( false, "Do not support octal or decimal encode constants");2972}2973fprintf(fp," }\n");29742975if( emit_position && (position != -1) && (oper.num_edges(globals) > 0) ) {2976fprintf(fp," virtual int %s_position() const { return %d; }\n", name, position);2977MemInterface *mem_interface = oper._interface->is_MemInterface();2978const char *base = mem_interface->_base;2979const char *disp = mem_interface->_disp;2980if( emit_position && (strcmp(name,"base") == 0)2981&& base != NULL && is_regI(base, oper, globals)2982&& disp != NULL && is_conP(disp, oper, globals) ) {2983// Found a memory access using a constant pointer for a displacement2984// and a base register containing an integer offset.2985// In this case the base and disp are reversed with respect to what2986// is expected by MachNode::get_base_and_disp() and MachNode::adr_type().2987// Provide a non-NULL return for disp_as_type() that will allow adr_type()2988// to correctly compute the access type for alias analysis.2989//2990// See BugId 4796752, operand indOffset32X in i486.ad2991int idx = rep_var_to_constant_index(disp, oper, globals);2992fprintf(fp," virtual const TypePtr *disp_as_type() const { return _c%d; }\n", idx);2993}2994}2995}29962997//2998// Construct the method to copy _idx, inputs and operands to new node.2999static void define_fill_new_machnode(bool used, FILE *fp_cpp) {3000fprintf(fp_cpp, "\n");3001fprintf(fp_cpp, "// Copy _idx, inputs and operands to new node\n");3002fprintf(fp_cpp, "void MachNode::fill_new_machnode( MachNode* node, Compile* C) const {\n");3003if( !used ) {3004fprintf(fp_cpp, " // This architecture does not have cisc or short branch instructions\n");3005fprintf(fp_cpp, " ShouldNotCallThis();\n");3006fprintf(fp_cpp, "}\n");3007} else {3008// New node must use same node index for access through allocator's tables3009fprintf(fp_cpp, " // New node must use same node index\n");3010fprintf(fp_cpp, " node->set_idx( _idx );\n");3011// Copy machine-independent inputs3012fprintf(fp_cpp, " // Copy machine-independent inputs\n");3013fprintf(fp_cpp, " for( uint j = 0; j < req(); j++ ) {\n");3014fprintf(fp_cpp, " node->add_req(in(j));\n");3015fprintf(fp_cpp, " }\n");3016// Copy machine operands to new MachNode3017fprintf(fp_cpp, " // Copy my operands, except for cisc position\n");3018fprintf(fp_cpp, " int nopnds = num_opnds();\n");3019fprintf(fp_cpp, " assert( node->num_opnds() == (uint)nopnds, \"Must have same number of operands\");\n");3020fprintf(fp_cpp, " MachOper **to = node->_opnds;\n");3021fprintf(fp_cpp, " for( int i = 0; i < nopnds; i++ ) {\n");3022fprintf(fp_cpp, " if( i != cisc_operand() ) \n");3023fprintf(fp_cpp, " to[i] = _opnds[i]->clone(C);\n");3024fprintf(fp_cpp, " }\n");3025fprintf(fp_cpp, "}\n");3026}3027fprintf(fp_cpp, "\n");3028}30293030//------------------------------defineClasses----------------------------------3031// Define members of MachNode and MachOper classes based on3032// operand and instruction lists3033void ArchDesc::defineClasses(FILE *fp) {30343035// Define the contents of an array containing the machine register names3036defineRegNames(fp, _register);3037// Define an array containing the machine register encoding values3038defineRegEncodes(fp, _register);3039// Generate an enumeration of user-defined register classes3040// and a list of register masks, one for each class.3041// Only define the RegMask value objects in the expand file.3042// Declare each as an extern const RegMask ...; in ad_<arch>.hpp3043declare_register_masks(_HPP_file._fp);3044// build_register_masks(fp);3045build_register_masks(_CPP_EXPAND_file._fp);3046// Define the pipe_classes3047build_pipe_classes(_CPP_PIPELINE_file._fp);30483049// Generate Machine Classes for each operand defined in AD file3050fprintf(fp,"\n");3051fprintf(fp,"\n");3052fprintf(fp,"//------------------Define classes derived from MachOper---------------------\n");3053// Iterate through all operands3054_operands.reset();3055OperandForm *oper;3056for( ; (oper = (OperandForm*)_operands.iter()) != NULL; ) {3057// Ensure this is a machine-world instruction3058if ( oper->ideal_only() ) continue;3059// !!!!!3060// The declaration of labelOper is in machine-independent file: machnode3061if ( strcmp(oper->_ident,"label") == 0 ) {3062defineIn_RegMask(_CPP_MISC_file._fp, _globalNames, *oper);30633064fprintf(fp,"MachOper *%sOper::clone(Compile* C) const {\n", oper->_ident);3065fprintf(fp," return new (C) %sOper(_label, _block_num);\n", oper->_ident);3066fprintf(fp,"}\n");30673068fprintf(fp,"uint %sOper::opcode() const { return %s; }\n",3069oper->_ident, machOperEnum(oper->_ident));3070// // Currently all XXXOper::Hash() methods are identical (990820)3071// define_hash(fp, oper->_ident);3072// // Currently all XXXOper::Cmp() methods are identical (990820)3073// define_cmp(fp, oper->_ident);3074fprintf(fp,"\n");30753076continue;3077}30783079// The declaration of methodOper is in machine-independent file: machnode3080if ( strcmp(oper->_ident,"method") == 0 ) {3081defineIn_RegMask(_CPP_MISC_file._fp, _globalNames, *oper);30823083fprintf(fp,"MachOper *%sOper::clone(Compile* C) const {\n", oper->_ident);3084fprintf(fp," return new (C) %sOper(_method);\n", oper->_ident);3085fprintf(fp,"}\n");30863087fprintf(fp,"uint %sOper::opcode() const { return %s; }\n",3088oper->_ident, machOperEnum(oper->_ident));3089// // Currently all XXXOper::Hash() methods are identical (990820)3090// define_hash(fp, oper->_ident);3091// // Currently all XXXOper::Cmp() methods are identical (990820)3092// define_cmp(fp, oper->_ident);3093fprintf(fp,"\n");30943095continue;3096}30973098defineIn_RegMask(fp, _globalNames, *oper);3099defineClone(_CPP_CLONE_file._fp, _globalNames, *oper);3100// // Currently all XXXOper::Hash() methods are identical (990820)3101// define_hash(fp, oper->_ident);3102// // Currently all XXXOper::Cmp() methods are identical (990820)3103// define_cmp(fp, oper->_ident);31043105// side-call to generate output that used to be in the header file:3106extern void gen_oper_format(FILE *fp, FormDict &globals, OperandForm &oper, bool for_c_file);3107gen_oper_format(_CPP_FORMAT_file._fp, _globalNames, *oper, true);31083109}311031113112// Generate Machine Classes for each instruction defined in AD file3113fprintf(fp,"//------------------Define members for classes derived from MachNode----------\n");3114// Output the definitions for out_RegMask() // & kill_RegMask()3115_instructions.reset();3116InstructForm *instr;3117MachNodeForm *machnode;3118for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3119// Ensure this is a machine-world instruction3120if ( instr->ideal_only() ) continue;31213122defineOut_RegMask(_CPP_MISC_file._fp, instr->_ident, reg_mask(*instr));3123}31243125bool used = false;3126// Output the definitions for expand rules & peephole rules3127_instructions.reset();3128for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3129// Ensure this is a machine-world instruction3130if ( instr->ideal_only() ) continue;3131// If there are multiple defs/kills, or an explicit expand rule, build rule3132if( instr->expands() || instr->needs_projections() ||3133instr->has_temps() ||3134instr->is_mach_constant() ||3135instr->needs_constant_base() ||3136instr->_matrule != NULL &&3137instr->num_opnds() != instr->num_unique_opnds() )3138defineExpand(_CPP_EXPAND_file._fp, instr);3139// If there is an explicit peephole rule, build it3140if ( instr->peepholes() )3141definePeephole(_CPP_PEEPHOLE_file._fp, instr);31423143// Output code to convert to the cisc version, if applicable3144used |= instr->define_cisc_version(*this, fp);31453146// Output code to convert to the short branch version, if applicable3147used |= instr->define_short_branch_methods(*this, fp);3148}31493150// Construct the method called by cisc_version() to copy inputs and operands.3151define_fill_new_machnode(used, fp);31523153// Output the definitions for labels3154_instructions.reset();3155while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {3156// Ensure this is a machine-world instruction3157if ( instr->ideal_only() ) continue;31583159// Access the fields for operand Label3160int label_position = instr->label_position();3161if( label_position != -1 ) {3162// Set the label3163fprintf(fp,"void %sNode::label_set( Label* label, uint block_num ) {\n", instr->_ident);3164fprintf(fp," labelOper* oper = (labelOper*)(opnd_array(%d));\n",3165label_position );3166fprintf(fp," oper->_label = label;\n");3167fprintf(fp," oper->_block_num = block_num;\n");3168fprintf(fp,"}\n");3169// Save the label3170fprintf(fp,"void %sNode::save_label( Label** label, uint* block_num ) {\n", instr->_ident);3171fprintf(fp," labelOper* oper = (labelOper*)(opnd_array(%d));\n",3172label_position );3173fprintf(fp," *label = oper->_label;\n");3174fprintf(fp," *block_num = oper->_block_num;\n");3175fprintf(fp,"}\n");3176}3177}31783179// Output the definitions for methods3180_instructions.reset();3181while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {3182// Ensure this is a machine-world instruction3183if ( instr->ideal_only() ) continue;31843185// Access the fields for operand Label3186int method_position = instr->method_position();3187if( method_position != -1 ) {3188// Access the method's address3189fprintf(fp,"void %sNode::method_set( intptr_t method ) {\n", instr->_ident);3190fprintf(fp," ((methodOper*)opnd_array(%d))->_method = method;\n",3191method_position );3192fprintf(fp,"}\n");3193fprintf(fp,"\n");3194}3195}31963197// Define this instruction's number of relocation entries, base is '0'3198_instructions.reset();3199while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {3200// Output the definition for number of relocation entries3201uint reloc_size = instr->reloc(_globalNames);3202if ( reloc_size != 0 ) {3203fprintf(fp,"int %sNode::reloc() const {\n", instr->_ident);3204fprintf(fp," return %d;\n", reloc_size);3205fprintf(fp,"}\n");3206fprintf(fp,"\n");3207}3208}3209fprintf(fp,"\n");32103211// Output the definitions for code generation3212//3213// address ___Node::emit(address ptr, PhaseRegAlloc *ra_) const {3214// // ... encoding defined by user3215// return ptr;3216// }3217//3218_instructions.reset();3219for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3220// Ensure this is a machine-world instruction3221if ( instr->ideal_only() ) continue;32223223if (instr->_insencode) {3224if (instr->postalloc_expands()) {3225// Don't write this to _CPP_EXPAND_file, as the code generated calls C-code3226// from code sections in ad file that is dumped to fp.3227define_postalloc_expand(fp, *instr);3228} else {3229defineEmit(fp, *instr);3230}3231}3232if (instr->is_mach_constant()) defineEvalConstant(fp, *instr);3233if (instr->_size) defineSize (fp, *instr);32343235// side-call to generate output that used to be in the header file:3236extern void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &oper, bool for_c_file);3237gen_inst_format(_CPP_FORMAT_file._fp, _globalNames, *instr, true);3238}32393240// Output the definitions for alias analysis3241_instructions.reset();3242for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3243// Ensure this is a machine-world instruction3244if ( instr->ideal_only() ) continue;32453246// Analyze machine instructions that either USE or DEF memory.3247int memory_operand = instr->memory_operand(_globalNames);32483249if ( memory_operand != InstructForm::NO_MEMORY_OPERAND ) {3250if( memory_operand == InstructForm::MANY_MEMORY_OPERANDS ) {3251fprintf(fp,"const TypePtr *%sNode::adr_type() const { return TypePtr::BOTTOM; }\n", instr->_ident);3252fprintf(fp,"const MachOper* %sNode::memory_operand() const { return (MachOper*)-1; }\n", instr->_ident);3253} else {3254fprintf(fp,"const MachOper* %sNode::memory_operand() const { return _opnds[%d]; }\n", instr->_ident, memory_operand);3255}3256}3257}32583259// Get the length of the longest identifier3260int max_ident_len = 0;3261_instructions.reset();32623263for ( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3264if (instr->_ins_pipe && _pipeline->_classlist.search(instr->_ins_pipe)) {3265int ident_len = (int)strlen(instr->_ident);3266if( max_ident_len < ident_len )3267max_ident_len = ident_len;3268}3269}32703271// Emit specifically for Node(s)3272fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline_class() { return %s; }\n",3273max_ident_len, "Node", _pipeline ? "(&pipeline_class_Zero_Instructions)" : "NULL");3274fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline() const { return %s; }\n",3275max_ident_len, "Node", _pipeline ? "(&pipeline_class_Zero_Instructions)" : "NULL");3276fprintf(_CPP_PIPELINE_file._fp, "\n");32773278fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline_class() { return %s; }\n",3279max_ident_len, "MachNode", _pipeline ? "(&pipeline_class_Unknown_Instructions)" : "NULL");3280fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*s::pipeline() const { return pipeline_class(); }\n",3281max_ident_len, "MachNode");3282fprintf(_CPP_PIPELINE_file._fp, "\n");32833284// Output the definitions for machine node specific pipeline data3285_machnodes.reset();32863287for ( ; (machnode = (MachNodeForm*)_machnodes.iter()) != NULL; ) {3288fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %sNode::pipeline() const { return (&pipeline_class_%03d); }\n",3289machnode->_ident, ((class PipeClassForm *)_pipeline->_classdict[machnode->_machnode_pipe])->_num);3290}32913292fprintf(_CPP_PIPELINE_file._fp, "\n");32933294// Output the definitions for instruction pipeline static data references3295_instructions.reset();32963297for ( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {3298if (instr->_ins_pipe && _pipeline->_classlist.search(instr->_ins_pipe)) {3299fprintf(_CPP_PIPELINE_file._fp, "\n");3300fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*sNode::pipeline_class() { return (&pipeline_class_%03d); }\n",3301max_ident_len, instr->_ident, ((class PipeClassForm *)_pipeline->_classdict[instr->_ins_pipe])->_num);3302fprintf(_CPP_PIPELINE_file._fp, "const Pipeline * %*sNode::pipeline() const { return (&pipeline_class_%03d); }\n",3303max_ident_len, instr->_ident, ((class PipeClassForm *)_pipeline->_classdict[instr->_ins_pipe])->_num);3304}3305}3306}330733083309// -------------------------------- maps ------------------------------------33103311// Information needed to generate the ReduceOp mapping for the DFA3312class OutputReduceOp : public OutputMap {3313public:3314OutputReduceOp(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3315: OutputMap(hpp, cpp, globals, AD, "reduceOp") {};33163317void declaration() { fprintf(_hpp, "extern const int reduceOp[];\n"); }3318void definition() { fprintf(_cpp, "const int reduceOp[] = {\n"); }3319void closing() { fprintf(_cpp, " 0 // no trailing comma\n");3320OutputMap::closing();3321}3322void map(OpClassForm &opc) {3323const char *reduce = opc._ident;3324if( reduce ) fprintf(_cpp, " %s_rule", reduce);3325else fprintf(_cpp, " 0");3326}3327void map(OperandForm &oper) {3328// Most operands without match rules, e.g. eFlagsReg, do not have a result operand3329const char *reduce = (oper._matrule ? oper.reduce_result() : NULL);3330// operand stackSlot does not have a match rule, but produces a stackSlot3331if( oper.is_user_name_for_sReg() != Form::none ) reduce = oper.reduce_result();3332if( reduce ) fprintf(_cpp, " %s_rule", reduce);3333else fprintf(_cpp, " 0");3334}3335void map(InstructForm &inst) {3336const char *reduce = (inst._matrule ? inst.reduce_result() : NULL);3337if( reduce ) fprintf(_cpp, " %s_rule", reduce);3338else fprintf(_cpp, " 0");3339}3340void map(char *reduce) {3341if( reduce ) fprintf(_cpp, " %s_rule", reduce);3342else fprintf(_cpp, " 0");3343}3344};33453346// Information needed to generate the LeftOp mapping for the DFA3347class OutputLeftOp : public OutputMap {3348public:3349OutputLeftOp(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3350: OutputMap(hpp, cpp, globals, AD, "leftOp") {};33513352void declaration() { fprintf(_hpp, "extern const int leftOp[];\n"); }3353void definition() { fprintf(_cpp, "const int leftOp[] = {\n"); }3354void closing() { fprintf(_cpp, " 0 // no trailing comma\n");3355OutputMap::closing();3356}3357void map(OpClassForm &opc) { fprintf(_cpp, " 0"); }3358void map(OperandForm &oper) {3359const char *reduce = oper.reduce_left(_globals);3360if( reduce ) fprintf(_cpp, " %s_rule", reduce);3361else fprintf(_cpp, " 0");3362}3363void map(char *name) {3364const char *reduce = _AD.reduceLeft(name);3365if( reduce ) fprintf(_cpp, " %s_rule", reduce);3366else fprintf(_cpp, " 0");3367}3368void map(InstructForm &inst) {3369const char *reduce = inst.reduce_left(_globals);3370if( reduce ) fprintf(_cpp, " %s_rule", reduce);3371else fprintf(_cpp, " 0");3372}3373};337433753376// Information needed to generate the RightOp mapping for the DFA3377class OutputRightOp : public OutputMap {3378public:3379OutputRightOp(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3380: OutputMap(hpp, cpp, globals, AD, "rightOp") {};33813382void declaration() { fprintf(_hpp, "extern const int rightOp[];\n"); }3383void definition() { fprintf(_cpp, "const int rightOp[] = {\n"); }3384void closing() { fprintf(_cpp, " 0 // no trailing comma\n");3385OutputMap::closing();3386}3387void map(OpClassForm &opc) { fprintf(_cpp, " 0"); }3388void map(OperandForm &oper) {3389const char *reduce = oper.reduce_right(_globals);3390if( reduce ) fprintf(_cpp, " %s_rule", reduce);3391else fprintf(_cpp, " 0");3392}3393void map(char *name) {3394const char *reduce = _AD.reduceRight(name);3395if( reduce ) fprintf(_cpp, " %s_rule", reduce);3396else fprintf(_cpp, " 0");3397}3398void map(InstructForm &inst) {3399const char *reduce = inst.reduce_right(_globals);3400if( reduce ) fprintf(_cpp, " %s_rule", reduce);3401else fprintf(_cpp, " 0");3402}3403};340434053406// Information needed to generate the Rule names for the DFA3407class OutputRuleName : public OutputMap {3408public:3409OutputRuleName(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3410: OutputMap(hpp, cpp, globals, AD, "ruleName") {};34113412void declaration() { fprintf(_hpp, "extern const char *ruleName[];\n"); }3413void definition() { fprintf(_cpp, "const char *ruleName[] = {\n"); }3414void closing() { fprintf(_cpp, " \"invalid rule name\" // no trailing comma\n");3415OutputMap::closing();3416}3417void map(OpClassForm &opc) { fprintf(_cpp, " \"%s\"", _AD.machOperEnum(opc._ident) ); }3418void map(OperandForm &oper) { fprintf(_cpp, " \"%s\"", _AD.machOperEnum(oper._ident) ); }3419void map(char *name) { fprintf(_cpp, " \"%s\"", name ? name : "0"); }3420void map(InstructForm &inst){ fprintf(_cpp, " \"%s\"", inst._ident ? inst._ident : "0"); }3421};342234233424// Information needed to generate the swallowed mapping for the DFA3425class OutputSwallowed : public OutputMap {3426public:3427OutputSwallowed(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3428: OutputMap(hpp, cpp, globals, AD, "swallowed") {};34293430void declaration() { fprintf(_hpp, "extern const bool swallowed[];\n"); }3431void definition() { fprintf(_cpp, "const bool swallowed[] = {\n"); }3432void closing() { fprintf(_cpp, " false // no trailing comma\n");3433OutputMap::closing();3434}3435void map(OperandForm &oper) { // Generate the entry for this opcode3436const char *swallowed = oper.swallowed(_globals) ? "true" : "false";3437fprintf(_cpp, " %s", swallowed);3438}3439void map(OpClassForm &opc) { fprintf(_cpp, " false"); }3440void map(char *name) { fprintf(_cpp, " false"); }3441void map(InstructForm &inst){ fprintf(_cpp, " false"); }3442};344334443445// Information needed to generate the decision array for instruction chain rule3446class OutputInstChainRule : public OutputMap {3447public:3448OutputInstChainRule(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)3449: OutputMap(hpp, cpp, globals, AD, "instruction_chain_rule") {};34503451void declaration() { fprintf(_hpp, "extern const bool instruction_chain_rule[];\n"); }3452void definition() { fprintf(_cpp, "const bool instruction_chain_rule[] = {\n"); }3453void closing() { fprintf(_cpp, " false // no trailing comma\n");3454OutputMap::closing();3455}3456void map(OpClassForm &opc) { fprintf(_cpp, " false"); }3457void map(OperandForm &oper) { fprintf(_cpp, " false"); }3458void map(char *name) { fprintf(_cpp, " false"); }3459void map(InstructForm &inst) { // Check for simple chain rule3460const char *chain = inst.is_simple_chain_rule(_globals) ? "true" : "false";3461fprintf(_cpp, " %s", chain);3462}3463};346434653466//---------------------------build_map------------------------------------3467// Build mapping from enumeration for densely packed operands3468// TO result and child types.3469void ArchDesc::build_map(OutputMap &map) {3470FILE *fp_hpp = map.decl_file();3471FILE *fp_cpp = map.def_file();3472int idx = 0;3473OperandForm *op;3474OpClassForm *opc;3475InstructForm *inst;34763477// Construct this mapping3478map.declaration();3479fprintf(fp_cpp,"\n");3480map.definition();34813482// Output the mapping for operands3483map.record_position(OutputMap::BEGIN_OPERANDS, idx );3484_operands.reset();3485for(; (op = (OperandForm*)_operands.iter()) != NULL; ) {3486// Ensure this is a machine-world instruction3487if ( op->ideal_only() ) continue;34883489// Generate the entry for this opcode3490fprintf(fp_cpp, " /* %4d */", idx); map.map(*op); fprintf(fp_cpp, ",\n");3491++idx;3492};3493fprintf(fp_cpp, " // last operand\n");34943495// Place all user-defined operand classes into the mapping3496map.record_position(OutputMap::BEGIN_OPCLASSES, idx );3497_opclass.reset();3498for(; (opc = (OpClassForm*)_opclass.iter()) != NULL; ) {3499fprintf(fp_cpp, " /* %4d */", idx); map.map(*opc); fprintf(fp_cpp, ",\n");3500++idx;3501};3502fprintf(fp_cpp, " // last operand class\n");35033504// Place all internally defined operands into the mapping3505map.record_position(OutputMap::BEGIN_INTERNALS, idx );3506_internalOpNames.reset();3507char *name = NULL;3508for(; (name = (char *)_internalOpNames.iter()) != NULL; ) {3509fprintf(fp_cpp, " /* %4d */", idx); map.map(name); fprintf(fp_cpp, ",\n");3510++idx;3511};3512fprintf(fp_cpp, " // last internally defined operand\n");35133514// Place all user-defined instructions into the mapping3515if( map.do_instructions() ) {3516map.record_position(OutputMap::BEGIN_INSTRUCTIONS, idx );3517// Output all simple instruction chain rules first3518map.record_position(OutputMap::BEGIN_INST_CHAIN_RULES, idx );3519{3520_instructions.reset();3521for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3522// Ensure this is a machine-world instruction3523if ( inst->ideal_only() ) continue;3524if ( ! inst->is_simple_chain_rule(_globalNames) ) continue;3525if ( inst->rematerialize(_globalNames, get_registers()) ) continue;35263527fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3528++idx;3529};3530map.record_position(OutputMap::BEGIN_REMATERIALIZE, idx );3531_instructions.reset();3532for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3533// Ensure this is a machine-world instruction3534if ( inst->ideal_only() ) continue;3535if ( ! inst->is_simple_chain_rule(_globalNames) ) continue;3536if ( ! inst->rematerialize(_globalNames, get_registers()) ) continue;35373538fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3539++idx;3540};3541map.record_position(OutputMap::END_INST_CHAIN_RULES, idx );3542}3543// Output all instructions that are NOT simple chain rules3544{3545_instructions.reset();3546for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3547// Ensure this is a machine-world instruction3548if ( inst->ideal_only() ) continue;3549if ( inst->is_simple_chain_rule(_globalNames) ) continue;3550if ( ! inst->rematerialize(_globalNames, get_registers()) ) continue;35513552fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3553++idx;3554};3555map.record_position(OutputMap::END_REMATERIALIZE, idx );3556_instructions.reset();3557for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {3558// Ensure this is a machine-world instruction3559if ( inst->ideal_only() ) continue;3560if ( inst->is_simple_chain_rule(_globalNames) ) continue;3561if ( inst->rematerialize(_globalNames, get_registers()) ) continue;35623563fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");3564++idx;3565};3566}3567fprintf(fp_cpp, " // last instruction\n");3568map.record_position(OutputMap::END_INSTRUCTIONS, idx );3569}3570// Finish defining table3571map.closing();3572};357335743575// Helper function for buildReduceMaps3576char reg_save_policy(const char *calling_convention) {3577char callconv;35783579if (!strcmp(calling_convention, "NS")) callconv = 'N';3580else if (!strcmp(calling_convention, "SOE")) callconv = 'E';3581else if (!strcmp(calling_convention, "SOC")) callconv = 'C';3582else if (!strcmp(calling_convention, "AS")) callconv = 'A';3583else callconv = 'Z';35843585return callconv;3586}35873588void ArchDesc::generate_needs_clone_jvms(FILE *fp_cpp) {3589fprintf(fp_cpp, "bool Compile::needs_clone_jvms() { return %s; }\n\n",3590_needs_clone_jvms ? "true" : "false");3591}35923593//---------------------------generate_assertion_checks-------------------3594void ArchDesc::generate_adlc_verification(FILE *fp_cpp) {3595fprintf(fp_cpp, "\n");35963597fprintf(fp_cpp, "#ifndef PRODUCT\n");3598fprintf(fp_cpp, "void Compile::adlc_verification() {\n");3599globalDefs().print_asserts(fp_cpp);3600fprintf(fp_cpp, "}\n");3601fprintf(fp_cpp, "#endif\n");3602fprintf(fp_cpp, "\n");3603}36043605//---------------------------addSourceBlocks-----------------------------3606void ArchDesc::addSourceBlocks(FILE *fp_cpp) {3607if (_source.count() > 0)3608_source.output(fp_cpp);36093610generate_adlc_verification(fp_cpp);3611}3612//---------------------------addHeaderBlocks-----------------------------3613void ArchDesc::addHeaderBlocks(FILE *fp_hpp) {3614if (_header.count() > 0)3615_header.output(fp_hpp);3616}3617//-------------------------addPreHeaderBlocks----------------------------3618void ArchDesc::addPreHeaderBlocks(FILE *fp_hpp) {3619// Output #defines from definition block3620globalDefs().print_defines(fp_hpp);36213622if (_pre_header.count() > 0)3623_pre_header.output(fp_hpp);3624}36253626//---------------------------buildReduceMaps-----------------------------3627// Build mapping from enumeration for densely packed operands3628// TO result and child types.3629void ArchDesc::buildReduceMaps(FILE *fp_hpp, FILE *fp_cpp) {3630RegDef *rdef;3631RegDef *next;36323633// The emit bodies currently require functions defined in the source block.36343635// Build external declarations for mappings3636fprintf(fp_hpp, "\n");3637fprintf(fp_hpp, "extern const char register_save_policy[];\n");3638fprintf(fp_hpp, "extern const char c_reg_save_policy[];\n");3639fprintf(fp_hpp, "extern const int register_save_type[];\n");3640fprintf(fp_hpp, "\n");36413642// Construct Save-Policy array3643fprintf(fp_cpp, "// Map from machine-independent register number to register_save_policy\n");3644fprintf(fp_cpp, "const char register_save_policy[] = {\n");3645_register->reset_RegDefs();3646for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {3647next = _register->iter_RegDefs();3648char policy = reg_save_policy(rdef->_callconv);3649const char *comma = (next != NULL) ? "," : " // no trailing comma";3650fprintf(fp_cpp, " '%c'%s // %s\n", policy, comma, rdef->_regname);3651}3652fprintf(fp_cpp, "};\n\n");36533654// Construct Native Save-Policy array3655fprintf(fp_cpp, "// Map from machine-independent register number to c_reg_save_policy\n");3656fprintf(fp_cpp, "const char c_reg_save_policy[] = {\n");3657_register->reset_RegDefs();3658for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {3659next = _register->iter_RegDefs();3660char policy = reg_save_policy(rdef->_c_conv);3661const char *comma = (next != NULL) ? "," : " // no trailing comma";3662fprintf(fp_cpp, " '%c'%s // %s\n", policy, comma, rdef->_regname);3663}3664fprintf(fp_cpp, "};\n\n");36653666// Construct Register Save Type array3667fprintf(fp_cpp, "// Map from machine-independent register number to register_save_type\n");3668fprintf(fp_cpp, "const int register_save_type[] = {\n");3669_register->reset_RegDefs();3670for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {3671next = _register->iter_RegDefs();3672const char *comma = (next != NULL) ? "," : " // no trailing comma";3673fprintf(fp_cpp, " %s%s\n", rdef->_idealtype, comma);3674}3675fprintf(fp_cpp, "};\n\n");36763677// Construct the table for reduceOp3678OutputReduceOp output_reduce_op(fp_hpp, fp_cpp, _globalNames, *this);3679build_map(output_reduce_op);3680// Construct the table for leftOp3681OutputLeftOp output_left_op(fp_hpp, fp_cpp, _globalNames, *this);3682build_map(output_left_op);3683// Construct the table for rightOp3684OutputRightOp output_right_op(fp_hpp, fp_cpp, _globalNames, *this);3685build_map(output_right_op);3686// Construct the table of rule names3687OutputRuleName output_rule_name(fp_hpp, fp_cpp, _globalNames, *this);3688build_map(output_rule_name);3689// Construct the boolean table for subsumed operands3690OutputSwallowed output_swallowed(fp_hpp, fp_cpp, _globalNames, *this);3691build_map(output_swallowed);3692// // // Preserve in case we decide to use this table instead of another3693//// Construct the boolean table for instruction chain rules3694//OutputInstChainRule output_inst_chain(fp_hpp, fp_cpp, _globalNames, *this);3695//build_map(output_inst_chain);36963697}369836993700//---------------------------buildMachOperGenerator---------------------------37013702// Recurse through match tree, building path through corresponding state tree,3703// Until we reach the constant we are looking for.3704static void path_to_constant(FILE *fp, FormDict &globals,3705MatchNode *mnode, uint idx) {3706if ( ! mnode) return;37073708unsigned position = 0;3709const char *result = NULL;3710const char *name = NULL;3711const char *optype = NULL;37123713// Base Case: access constant in ideal node linked to current state node3714// Each type of constant has its own access function3715if ( (mnode->_lChild == NULL) && (mnode->_rChild == NULL)3716&& mnode->base_operand(position, globals, result, name, optype) ) {3717if ( strcmp(optype,"ConI") == 0 ) {3718fprintf(fp, "_leaf->get_int()");3719} else if ( (strcmp(optype,"ConP") == 0) ) {3720fprintf(fp, "_leaf->bottom_type()->is_ptr()");3721} else if ( (strcmp(optype,"ConN") == 0) ) {3722fprintf(fp, "_leaf->bottom_type()->is_narrowoop()");3723} else if ( (strcmp(optype,"ConNKlass") == 0) ) {3724fprintf(fp, "_leaf->bottom_type()->is_narrowklass()");3725} else if ( (strcmp(optype,"ConF") == 0) ) {3726fprintf(fp, "_leaf->getf()");3727} else if ( (strcmp(optype,"ConD") == 0) ) {3728fprintf(fp, "_leaf->getd()");3729} else if ( (strcmp(optype,"ConL") == 0) ) {3730fprintf(fp, "_leaf->get_long()");3731} else if ( (strcmp(optype,"Con")==0) ) {3732// !!!!! - Update if adding a machine-independent constant type3733fprintf(fp, "_leaf->get_int()");3734assert( false, "Unsupported constant type, pointer or indefinite");3735} else if ( (strcmp(optype,"Bool") == 0) ) {3736fprintf(fp, "_leaf->as_Bool()->_test._test");3737} else {3738assert( false, "Unsupported constant type");3739}3740return;3741}37423743// If constant is in left child, build path and recurse3744uint lConsts = (mnode->_lChild) ? (mnode->_lChild->num_consts(globals) ) : 0;3745uint rConsts = (mnode->_rChild) ? (mnode->_rChild->num_consts(globals) ) : 0;3746if ( (mnode->_lChild) && (lConsts > idx) ) {3747fprintf(fp, "_kids[0]->");3748path_to_constant(fp, globals, mnode->_lChild, idx);3749return;3750}3751// If constant is in right child, build path and recurse3752if ( (mnode->_rChild) && (rConsts > (idx - lConsts) ) ) {3753idx = idx - lConsts;3754fprintf(fp, "_kids[1]->");3755path_to_constant(fp, globals, mnode->_rChild, idx);3756return;3757}3758assert( false, "ShouldNotReachHere()");3759}37603761// Generate code that is executed when generating a specific Machine Operand3762static void genMachOperCase(FILE *fp, FormDict &globalNames, ArchDesc &AD,3763OperandForm &op) {3764const char *opName = op._ident;3765const char *opEnumName = AD.machOperEnum(opName);3766uint num_consts = op.num_consts(globalNames);37673768// Generate the case statement for this opcode3769fprintf(fp, " case %s:", opEnumName);3770fprintf(fp, "\n return new (C) %sOper(", opName);3771// Access parameters for constructor from the stat object3772//3773// Build access to condition code value3774if ( (num_consts > 0) ) {3775uint i = 0;3776path_to_constant(fp, globalNames, op._matrule, i);3777for ( i = 1; i < num_consts; ++i ) {3778fprintf(fp, ", ");3779path_to_constant(fp, globalNames, op._matrule, i);3780}3781}3782fprintf(fp, " );\n");3783}378437853786// Build switch to invoke "new" MachNode or MachOper3787void ArchDesc::buildMachOperGenerator(FILE *fp_cpp) {3788int idx = 0;37893790// Build switch to invoke 'new' for a specific MachOper3791fprintf(fp_cpp, "\n");3792fprintf(fp_cpp, "\n");3793fprintf(fp_cpp,3794"//------------------------- MachOper Generator ---------------\n");3795fprintf(fp_cpp,3796"// A switch statement on the dense-packed user-defined type system\n"3797"// that invokes 'new' on the corresponding class constructor.\n");3798fprintf(fp_cpp, "\n");3799fprintf(fp_cpp, "MachOper *State::MachOperGenerator");3800fprintf(fp_cpp, "(int opcode, Compile* C)");3801fprintf(fp_cpp, "{\n");3802fprintf(fp_cpp, "\n");3803fprintf(fp_cpp, " switch(opcode) {\n");38043805// Place all user-defined operands into the mapping3806_operands.reset();3807int opIndex = 0;3808OperandForm *op;3809for( ; (op = (OperandForm*)_operands.iter()) != NULL; ) {3810// Ensure this is a machine-world instruction3811if ( op->ideal_only() ) continue;38123813genMachOperCase(fp_cpp, _globalNames, *this, *op);3814};38153816// Do not iterate over operand classes for the operand generator!!!38173818// Place all internal operands into the mapping3819_internalOpNames.reset();3820const char *iopn;3821for( ; (iopn = _internalOpNames.iter()) != NULL; ) {3822const char *opEnumName = machOperEnum(iopn);3823// Generate the case statement for this opcode3824fprintf(fp_cpp, " case %s:", opEnumName);3825fprintf(fp_cpp, " return NULL;\n");3826};38273828// Generate the default case for switch(opcode)3829fprintf(fp_cpp, " \n");3830fprintf(fp_cpp, " default:\n");3831fprintf(fp_cpp, " fprintf(stderr, \"Default MachOper Generator invoked for: \\n\");\n");3832fprintf(fp_cpp, " fprintf(stderr, \" opcode = %cd\\n\", opcode);\n", '%');3833fprintf(fp_cpp, " break;\n");3834fprintf(fp_cpp, " }\n");38353836// Generate the closing for method Matcher::MachOperGenerator3837fprintf(fp_cpp, " return NULL;\n");3838fprintf(fp_cpp, "};\n");3839}384038413842//---------------------------buildMachNode-------------------------------------3843// Build a new MachNode, for MachNodeGenerator or cisc-spilling3844void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *indent) {3845const char *opType = NULL;3846const char *opClass = inst->_ident;38473848// Create the MachNode object3849fprintf(fp_cpp, "%s %sNode *node = new (C) %sNode();\n",indent, opClass,opClass);38503851if ( (inst->num_post_match_opnds() != 0) ) {3852// Instruction that contains operands which are not in match rule.3853//3854// Check if the first post-match component may be an interesting def3855bool dont_care = false;3856ComponentList &comp_list = inst->_components;3857Component *comp = NULL;3858comp_list.reset();3859if ( comp_list.match_iter() != NULL ) dont_care = true;38603861// Insert operands that are not in match-rule.3862// Only insert a DEF if the do_care flag is set3863comp_list.reset();3864while ( comp = comp_list.post_match_iter() ) {3865// Check if we don't care about DEFs or KILLs that are not USEs3866if ( dont_care && (! comp->isa(Component::USE)) ) {3867continue;3868}3869dont_care = true;3870// For each operand not in the match rule, call MachOperGenerator3871// with the enum for the opcode that needs to be built.3872ComponentList clist = inst->_components;3873int index = clist.operand_position(comp->_name, comp->_usedef, inst);3874const char *opcode = machOperEnum(comp->_type);3875fprintf(fp_cpp, "%s node->set_opnd_array(%d, ", indent, index);3876fprintf(fp_cpp, "MachOperGenerator(%s, C));\n", opcode);3877}3878}3879else if ( inst->is_chain_of_constant(_globalNames, opType) ) {3880// An instruction that chains from a constant!3881// In this case, we need to subsume the constant into the node3882// at operand position, oper_input_base().3883//3884// Fill in the constant3885fprintf(fp_cpp, "%s node->_opnd_array[%d] = ", indent,3886inst->oper_input_base(_globalNames));3887// #####3888// Check for multiple constants and then fill them in.3889// Just like MachOperGenerator3890const char *opName = inst->_matrule->_rChild->_opType;3891fprintf(fp_cpp, "new (C) %sOper(", opName);3892// Grab operand form3893OperandForm *op = (_globalNames[opName])->is_operand();3894// Look up the number of constants3895uint num_consts = op->num_consts(_globalNames);3896if ( (num_consts > 0) ) {3897uint i = 0;3898path_to_constant(fp_cpp, _globalNames, op->_matrule, i);3899for ( i = 1; i < num_consts; ++i ) {3900fprintf(fp_cpp, ", ");3901path_to_constant(fp_cpp, _globalNames, op->_matrule, i);3902}3903}3904fprintf(fp_cpp, " );\n");3905// #####3906}39073908// Fill in the bottom_type where requested3909if (inst->captures_bottom_type(_globalNames)) {3910if (strncmp("MachCall", inst->mach_base_class(_globalNames), strlen("MachCall"))) {3911fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);3912}3913}3914if( inst->is_ideal_if() ) {3915fprintf(fp_cpp, "%s node->_prob = _leaf->as_If()->_prob;\n", indent);3916fprintf(fp_cpp, "%s node->_fcnt = _leaf->as_If()->_fcnt;\n", indent);3917}3918if( inst->is_ideal_fastlock() ) {3919fprintf(fp_cpp, "%s node->_counters = _leaf->as_FastLock()->counters();\n", indent);3920fprintf(fp_cpp, "%s node->_rtm_counters = _leaf->as_FastLock()->rtm_counters();\n", indent);3921fprintf(fp_cpp, "%s node->_stack_rtm_counters = _leaf->as_FastLock()->stack_rtm_counters();\n", indent);3922}39233924}39253926//---------------------------declare_cisc_version------------------------------3927// Build CISC version of this instruction3928void InstructForm::declare_cisc_version(ArchDesc &AD, FILE *fp_hpp) {3929if( AD.can_cisc_spill() ) {3930InstructForm *inst_cisc = cisc_spill_alternate();3931if (inst_cisc != NULL) {3932fprintf(fp_hpp, " virtual int cisc_operand() const { return %d; }\n", cisc_spill_operand());3933fprintf(fp_hpp, " virtual MachNode *cisc_version(int offset, Compile* C);\n");3934fprintf(fp_hpp, " virtual void use_cisc_RegMask();\n");3935fprintf(fp_hpp, " virtual const RegMask *cisc_RegMask() const { return _cisc_RegMask; }\n");3936}3937}3938}39393940//---------------------------define_cisc_version-------------------------------3941// Build CISC version of this instruction3942bool InstructForm::define_cisc_version(ArchDesc &AD, FILE *fp_cpp) {3943InstructForm *inst_cisc = this->cisc_spill_alternate();3944if( AD.can_cisc_spill() && (inst_cisc != NULL) ) {3945const char *name = inst_cisc->_ident;3946assert( inst_cisc->num_opnds() == this->num_opnds(), "Must have same number of operands");3947OperandForm *cisc_oper = AD.cisc_spill_operand();3948assert( cisc_oper != NULL, "insanity check");3949const char *cisc_oper_name = cisc_oper->_ident;3950assert( cisc_oper_name != NULL, "insanity check");3951//3952// Set the correct reg_mask_or_stack for the cisc operand3953fprintf(fp_cpp, "\n");3954fprintf(fp_cpp, "void %sNode::use_cisc_RegMask() {\n", this->_ident);3955// Lookup the correct reg_mask_or_stack3956const char *reg_mask_name = cisc_reg_mask_name();3957fprintf(fp_cpp, " _cisc_RegMask = &STACK_OR_%s;\n", reg_mask_name);3958fprintf(fp_cpp, "}\n");3959//3960// Construct CISC version of this instruction3961fprintf(fp_cpp, "\n");3962fprintf(fp_cpp, "// Build CISC version of this instruction\n");3963fprintf(fp_cpp, "MachNode *%sNode::cisc_version( int offset, Compile* C ) {\n", this->_ident);3964// Create the MachNode object3965fprintf(fp_cpp, " %sNode *node = new (C) %sNode();\n", name, name);3966// Fill in the bottom_type where requested3967if ( this->captures_bottom_type(AD.globalNames()) ) {3968fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");3969}39703971uint cur_num_opnds = num_opnds();3972if (cur_num_opnds > 1 && cur_num_opnds != num_unique_opnds()) {3973fprintf(fp_cpp," node->_num_opnds = %d;\n", num_unique_opnds());3974}39753976fprintf(fp_cpp, "\n");3977fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n");3978fprintf(fp_cpp, " fill_new_machnode(node, C);\n");3979// Construct operand to access [stack_pointer + offset]3980fprintf(fp_cpp, " // Construct operand to access [stack_pointer + offset]\n");3981fprintf(fp_cpp, " node->set_opnd_array(cisc_operand(), new (C) %sOper(offset));\n", cisc_oper_name);3982fprintf(fp_cpp, "\n");39833984// Return result and exit scope3985fprintf(fp_cpp, " return node;\n");3986fprintf(fp_cpp, "}\n");3987fprintf(fp_cpp, "\n");3988return true;3989}3990return false;3991}39923993//---------------------------declare_short_branch_methods----------------------3994// Build prototypes for short branch methods3995void InstructForm::declare_short_branch_methods(FILE *fp_hpp) {3996if (has_short_branch_form()) {3997fprintf(fp_hpp, " virtual MachNode *short_branch_version(Compile* C);\n");3998}3999}40004001//---------------------------define_short_branch_methods-----------------------4002// Build definitions for short branch methods4003bool InstructForm::define_short_branch_methods(ArchDesc &AD, FILE *fp_cpp) {4004if (has_short_branch_form()) {4005InstructForm *short_branch = short_branch_form();4006const char *name = short_branch->_ident;40074008// Construct short_branch_version() method.4009fprintf(fp_cpp, "// Build short branch version of this instruction\n");4010fprintf(fp_cpp, "MachNode *%sNode::short_branch_version(Compile* C) {\n", this->_ident);4011// Create the MachNode object4012fprintf(fp_cpp, " %sNode *node = new (C) %sNode();\n", name, name);4013if( is_ideal_if() ) {4014fprintf(fp_cpp, " node->_prob = _prob;\n");4015fprintf(fp_cpp, " node->_fcnt = _fcnt;\n");4016}4017// Fill in the bottom_type where requested4018if ( this->captures_bottom_type(AD.globalNames()) ) {4019fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");4020}40214022fprintf(fp_cpp, "\n");4023// Short branch version must use same node index for access4024// through allocator's tables4025fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n");4026fprintf(fp_cpp, " fill_new_machnode(node, C);\n");40274028// Return result and exit scope4029fprintf(fp_cpp, " return node;\n");4030fprintf(fp_cpp, "}\n");4031fprintf(fp_cpp,"\n");4032return true;4033}4034return false;4035}403640374038//---------------------------buildMachNodeGenerator----------------------------4039// Build switch to invoke appropriate "new" MachNode for an opcode4040void ArchDesc::buildMachNodeGenerator(FILE *fp_cpp) {40414042// Build switch to invoke 'new' for a specific MachNode4043fprintf(fp_cpp, "\n");4044fprintf(fp_cpp, "\n");4045fprintf(fp_cpp,4046"//------------------------- MachNode Generator ---------------\n");4047fprintf(fp_cpp,4048"// A switch statement on the dense-packed user-defined type system\n"4049"// that invokes 'new' on the corresponding class constructor.\n");4050fprintf(fp_cpp, "\n");4051fprintf(fp_cpp, "MachNode *State::MachNodeGenerator");4052fprintf(fp_cpp, "(int opcode, Compile* C)");4053fprintf(fp_cpp, "{\n");4054fprintf(fp_cpp, " switch(opcode) {\n");40554056// Provide constructor for all user-defined instructions4057_instructions.reset();4058int opIndex = operandFormCount();4059InstructForm *inst;4060for( ; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {4061// Ensure that matrule is defined.4062if ( inst->_matrule == NULL ) continue;40634064int opcode = opIndex++;4065const char *opClass = inst->_ident;4066char *opType = NULL;40674068// Generate the case statement for this instruction4069fprintf(fp_cpp, " case %s_rule:", opClass);40704071// Start local scope4072fprintf(fp_cpp, " {\n");4073// Generate code to construct the new MachNode4074buildMachNode(fp_cpp, inst, " ");4075// Return result and exit scope4076fprintf(fp_cpp, " return node;\n");4077fprintf(fp_cpp, " }\n");4078}40794080// Generate the default case for switch(opcode)4081fprintf(fp_cpp, " \n");4082fprintf(fp_cpp, " default:\n");4083fprintf(fp_cpp, " fprintf(stderr, \"Default MachNode Generator invoked for: \\n\");\n");4084fprintf(fp_cpp, " fprintf(stderr, \" opcode = %cd\\n\", opcode);\n", '%');4085fprintf(fp_cpp, " break;\n");4086fprintf(fp_cpp, " };\n");40874088// Generate the closing for method Matcher::MachNodeGenerator4089fprintf(fp_cpp, " return NULL;\n");4090fprintf(fp_cpp, "}\n");4091}409240934094//---------------------------buildInstructMatchCheck--------------------------4095// Output the method to Matcher which checks whether or not a specific4096// instruction has a matching rule for the host architecture.4097void ArchDesc::buildInstructMatchCheck(FILE *fp_cpp) const {4098fprintf(fp_cpp, "\n\n");4099fprintf(fp_cpp, "const bool Matcher::has_match_rule(int opcode) {\n");4100fprintf(fp_cpp, " assert(_last_machine_leaf < opcode && opcode < _last_opcode, \"opcode in range\");\n");4101fprintf(fp_cpp, " return _hasMatchRule[opcode];\n");4102fprintf(fp_cpp, "}\n\n");41034104fprintf(fp_cpp, "const bool Matcher::_hasMatchRule[_last_opcode] = {\n");4105int i;4106for (i = 0; i < _last_opcode - 1; i++) {4107fprintf(fp_cpp, " %-5s, // %s\n",4108_has_match_rule[i] ? "true" : "false",4109NodeClassNames[i]);4110}4111fprintf(fp_cpp, " %-5s // %s\n",4112_has_match_rule[i] ? "true" : "false",4113NodeClassNames[i]);4114fprintf(fp_cpp, "};\n");4115}41164117//---------------------------buildFrameMethods---------------------------------4118// Output the methods to Matcher which specify frame behavior4119void ArchDesc::buildFrameMethods(FILE *fp_cpp) {4120fprintf(fp_cpp,"\n\n");4121// Stack Direction4122fprintf(fp_cpp,"bool Matcher::stack_direction() const { return %s; }\n\n",4123_frame->_direction ? "true" : "false");4124// Sync Stack Slots4125fprintf(fp_cpp,"int Compile::sync_stack_slots() const { return %s; }\n\n",4126_frame->_sync_stack_slots);4127// Java Stack Alignment4128fprintf(fp_cpp,"uint Matcher::stack_alignment_in_bytes() { return %s; }\n\n",4129_frame->_alignment);4130// Java Return Address Location4131fprintf(fp_cpp,"OptoReg::Name Matcher::return_addr() const {");4132if (_frame->_return_addr_loc) {4133fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4134_frame->_return_addr);4135}4136else {4137fprintf(fp_cpp," return OptoReg::stack2reg(%s); }\n\n",4138_frame->_return_addr);4139}4140// Java Stack Slot Preservation4141fprintf(fp_cpp,"uint Compile::in_preserve_stack_slots() ");4142fprintf(fp_cpp,"{ return %s; }\n\n", _frame->_in_preserve_slots);4143// Top Of Stack Slot Preservation, for both Java and C4144fprintf(fp_cpp,"uint Compile::out_preserve_stack_slots() ");4145fprintf(fp_cpp,"{ return SharedRuntime::out_preserve_stack_slots(); }\n\n");4146// varargs C out slots killed4147fprintf(fp_cpp,"uint Compile::varargs_C_out_slots_killed() const ");4148fprintf(fp_cpp,"{ return %s; }\n\n", _frame->_varargs_C_out_slots_killed);4149// Java Argument Position4150fprintf(fp_cpp,"void Matcher::calling_convention(BasicType *sig_bt, VMRegPair *regs, uint length, bool is_outgoing) {\n");4151fprintf(fp_cpp,"%s\n", _frame->_calling_convention);4152fprintf(fp_cpp,"}\n\n");4153// Native Argument Position4154fprintf(fp_cpp,"void Matcher::c_calling_convention(BasicType *sig_bt, VMRegPair *regs, uint length) {\n");4155fprintf(fp_cpp,"%s\n", _frame->_c_calling_convention);4156fprintf(fp_cpp,"}\n\n");4157// Java Return Value Location4158fprintf(fp_cpp,"OptoRegPair Matcher::return_value(uint ideal_reg, bool is_outgoing) {\n");4159fprintf(fp_cpp,"%s\n", _frame->_return_value);4160fprintf(fp_cpp,"}\n\n");4161// Native Return Value Location4162fprintf(fp_cpp,"OptoRegPair Matcher::c_return_value(uint ideal_reg, bool is_outgoing) {\n");4163fprintf(fp_cpp,"%s\n", _frame->_c_return_value);4164fprintf(fp_cpp,"}\n\n");41654166// Inline Cache Register, mask definition, and encoding4167fprintf(fp_cpp,"OptoReg::Name Matcher::inline_cache_reg() {");4168fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4169_frame->_inline_cache_reg);4170fprintf(fp_cpp,"int Matcher::inline_cache_reg_encode() {");4171fprintf(fp_cpp," return _regEncode[inline_cache_reg()]; }\n\n");41724173// Interpreter's Method Oop Register, mask definition, and encoding4174fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_method_oop_reg() {");4175fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",4176_frame->_interpreter_method_oop_reg);4177fprintf(fp_cpp,"int Matcher::interpreter_method_oop_reg_encode() {");4178fprintf(fp_cpp," return _regEncode[interpreter_method_oop_reg()]; }\n\n");41794180// Interpreter's Frame Pointer Register, mask definition, and encoding4181fprintf(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