products/Sources/formale Sprachen/Java/openjdk-20-36_src/src/hotspot/share/adlc image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei:   Sprache: XML

/*
 * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */


// output_c.cpp - Class CPP file output routines for architecture definition

#include "adlc.hpp"

// Utilities to characterize effect statements
static bool is_def(int usedef) {
  switch(usedef) {
  case Component::DEF:
  case Component::USE_DEF: return truebreak;
  }
  return false;
}

// Define  an array containing the machine register names, strings.
static void defineRegNames(FILE *fp, RegisterForm *registers) {
  if (registers) {
    fprintf(fp,"\n");
    fprintf(fp,"// An array of character pointers to machine register names.\n");
    fprintf(fp,"const char *Matcher::regName[REG_COUNT] = {\n");

    // Output the register name for each register in the allocation classes
    RegDef *reg_def = NULL;
    RegDef *next = NULL;
    registers->reset_RegDefs();
    for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) {
      next = registers->iter_RegDefs();
      const char *comma = (next != NULL) ? "," : " // no trailing comma";
      fprintf(fp," \"%s\"%s\n", reg_def->_regname, comma);
    }

    // Finish defining enumeration
    fprintf(fp,"};\n");

    fprintf(fp,"\n");
    fprintf(fp,"// An array of character pointers to machine register names.\n");
    fprintf(fp,"const VMReg OptoReg::opto2vm[REG_COUNT] = {\n");
    reg_def = NULL;
    next = NULL;
    registers->reset_RegDefs();
    for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) {
      next = registers->iter_RegDefs();
      const char *comma = (next != NULL) ? "," : " // no trailing comma";
      fprintf(fp,"\t%s%s\n", reg_def->_concrete, comma);
    }
    // Finish defining array
    fprintf(fp,"\t};\n");
    fprintf(fp,"\n");

    fprintf(fp," OptoReg::Name OptoReg::vm2opto[ConcreteRegisterImpl::number_of_registers];\n");

  }
}

// Define an array containing the machine register encoding values
static void defineRegEncodes(FILE *fp, RegisterForm *registers) {
  if (registers) {
    fprintf(fp,"\n");
    fprintf(fp,"// An array of the machine register encode values\n");
    fprintf(fp,"const unsigned char Matcher::_regEncode[REG_COUNT] = {\n");

    // Output the register encoding for each register in the allocation classes
    RegDef *reg_def = NULL;
    RegDef *next    = NULL;
    registers->reset_RegDefs();
    for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) {
      next = registers->iter_RegDefs();
      const char* register_encode = reg_def->register_encode();
      const char *comma = (next != NULL) ? "," : " // no trailing comma";
      int encval;
      if (!ADLParser::is_int_token(register_encode, encval)) {
        fprintf(fp," %s%s // %s\n", register_encode, comma, reg_def->_regname);
      } else {
        // Output known constants in hex char format (backward compatibility).
        assert(encval < 256, "Exceeded supported width for register encoding");
        fprintf(fp," (unsigned char)'\\x%X'%s // %s\n", encval, comma, reg_def->_regname);
      }
    }
    // Finish defining enumeration
    fprintf(fp,"};\n");

  } // Done defining array
}

// Output an enumeration of register class names
static void defineRegClassEnum(FILE *fp, RegisterForm *registers) {
  if (registers) {
    // Output an enumeration of register class names
    fprintf(fp,"\n");
    fprintf(fp,"// Enumeration of register class names\n");
    fprintf(fp, "enum machRegisterClass {\n");
    registers->_rclasses.reset();
    for (const char *class_name = NULL; (class_name = registers->_rclasses.iter()) != NULL;) {
      const char * class_name_to_upper = toUpper(class_name);
      fprintf(fp," %s,\n", class_name_to_upper);
      delete[] class_name_to_upper;
    }
    // Finish defining enumeration
    fprintf(fp, " _last_Mach_Reg_Class\n");
    fprintf(fp, "};\n");
  }
}

// Declare an enumeration of user-defined register classes
// and a list of register masks, one for each class.
void ArchDesc::declare_register_masks(FILE *fp_hpp) {
  const char  *rc_name;

  if (_register) {
    // Build enumeration of user-defined register classes.
    defineRegClassEnum(fp_hpp, _register);

    // Generate a list of register masks, one for each class.
    fprintf(fp_hpp,"\n");
    fprintf(fp_hpp,"// Register masks, one for each register class.\n");
    _register->_rclasses.reset();
    for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) {
      RegClass *reg_class = _register->getRegClass(rc_name);
      assert(reg_class, "Using an undefined register class");
      reg_class->declare_register_masks(fp_hpp);
    }
  }
}

// Generate an enumeration of user-defined register classes
// and a list of register masks, one for each class.
void ArchDesc::build_register_masks(FILE *fp_cpp) {
  const char  *rc_name;

  if (_register) {
    // Generate a list of register masks, one for each class.
    fprintf(fp_cpp,"\n");
    fprintf(fp_cpp,"// Register masks, one for each register class.\n");
    _register->_rclasses.reset();
    for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) {
      RegClass *reg_class = _register->getRegClass(rc_name);
      assert(reg_class, "Using an undefined register class");
      reg_class->build_register_masks(fp_cpp);
    }
  }
}

// Compute an index for an array in the pipeline_reads_NNN arrays
static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, PipeClassForm *pipeclass)
{
  int templen = 1;
  int paramcount = 0;
  const char *paramname;

  if (pipeclass->_parameters.count() == 0)
    return -1;

  pipeclass->_parameters.reset();
  paramname = pipeclass->_parameters.iter();
  const PipeClassOperandForm *pipeopnd =
    (const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
  if (pipeopnd && !pipeopnd->isWrite() && strcmp(pipeopnd->_stage, "Universal"))
    pipeclass->_parameters.reset();

  while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {
    const PipeClassOperandForm *tmppipeopnd =
        (const PipeClassOperandForm *)pipeclass->_localUsage[paramname];

    if (tmppipeopnd)
      templen += 10 + (int)strlen(tmppipeopnd->_stage);
    else
      templen += 19;

    paramcount++;
  }

  // See if the count is zero
  if (paramcount == 0) {
    return -1;
  }

  char *operand_stages = new char [templen];
  operand_stages[0] = 0;
  int i = 0;
  templen = 0;

  pipeclass->_parameters.reset();
  paramname = pipeclass->_parameters.iter();
  pipeopnd = (const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
  if (pipeopnd && !pipeopnd->isWrite() && strcmp(pipeopnd->_stage, "Universal"))
    pipeclass->_parameters.reset();

  while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {
    const PipeClassOperandForm *tmppipeopnd =
        (const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
    templen += sprintf(&operand_stages[templen], " stage_%s%c\n",
      tmppipeopnd ? tmppipeopnd->_stage : "undefined",
      (++i < paramcount ? ',' : ' ') );
  }

  // See if the same string is in the table
  int ndx = pipeline_reads.index(operand_stages);

  // No, add it to the table
  if (ndx < 0) {
    pipeline_reads.addName(operand_stages);
    ndx = pipeline_reads.index(operand_stages);

    fprintf(fp_cpp, "static const enum machPipelineStages pipeline_reads_%03d[%d] = {\n%s};\n\n",
      ndx+1, paramcount, operand_stages);
  }
  else
    delete [] operand_stages;

  return (ndx);
}

// Compute an index for an array in the pipeline_res_stages_NNN arrays
static int pipeline_res_stages_initializer(
  FILE *fp_cpp,
  PipelineForm *pipeline,
  NameList &pipeline_res_stages,
  PipeClassForm *pipeclass)
{
  const PipeClassResourceForm *piperesource;
  int * res_stages = new int [pipeline->_rescount];
  int i;

  for (i = 0; i < pipeline->_rescount; i++)
     res_stages[i] = 0;

  for (pipeclass->_resUsage.reset();
       (piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {
    int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask();
    for (i = 0; i < pipeline->_rescount; i++)
      if ((1 << i) & used_mask) {
        int stage = pipeline->_stages.index(piperesource->_stage);
        if (res_stages[i] < stage+1)
          res_stages[i] = stage+1;
      }
  }

  // Compute the length needed for the resource list
  int commentlen = 0;
  int max_stage = 0;
  for (i = 0; i < pipeline->_rescount; i++) {
    if (res_stages[i] == 0) {
      if (max_stage < 9)
        max_stage = 9;
    }
    else {
      int stagelen = (int)strlen(pipeline->_stages.name(res_stages[i]-1));
      if (max_stage < stagelen)
        max_stage = stagelen;
    }

    commentlen += (int)strlen(pipeline->_reslist.name(i));
  }

  int templen = 1 + commentlen + pipeline->_rescount * (max_stage + 14);

  // Allocate space for the resource list
  char * resource_stages = new char [templen];

  templen = 0;
  for (i = 0; i < pipeline->_rescount; i++) {
    const char * const resname =
      res_stages[i] == 0 ? "undefined" : pipeline->_stages.name(res_stages[i]-1);

    templen += sprintf(&resource_stages[templen], " stage_%s%-*s // %s\n",
      resname, max_stage - (int)strlen(resname) + 1,
      (i < pipeline->_rescount-1) ? "," : "",
      pipeline->_reslist.name(i));
  }

  // See if the same string is in the table
  int ndx = pipeline_res_stages.index(resource_stages);

  // No, add it to the table
  if (ndx < 0) {
    pipeline_res_stages.addName(resource_stages);
    ndx = pipeline_res_stages.index(resource_stages);

    fprintf(fp_cpp, "static const enum machPipelineStages pipeline_res_stages_%03d[%d] = {\n%s};\n\n",
      ndx+1, pipeline->_rescount, resource_stages);
  }
  else
    delete [] resource_stages;

  delete [] res_stages;

  return (ndx);
}

// Compute an index for an array in the pipeline_res_cycles_NNN arrays
static int pipeline_res_cycles_initializer(
  FILE *fp_cpp,
  PipelineForm *pipeline,
  NameList &pipeline_res_cycles,
  PipeClassForm *pipeclass)
{
  const PipeClassResourceForm *piperesource;
  int * res_cycles = new int [pipeline->_rescount];
  int i;

  for (i = 0; i < pipeline->_rescount; i++)
     res_cycles[i] = 0;

  for (pipeclass->_resUsage.reset();
       (piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {
    int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask();
    for (i = 0; i < pipeline->_rescount; i++)
      if ((1 << i) & used_mask) {
        int cycles = piperesource->_cycles;
        if (res_cycles[i] < cycles)
          res_cycles[i] = cycles;
      }
  }

  // Pre-compute the string length
  int templen;
  int cyclelen = 0, commentlen = 0;
  int max_cycles = 0;
  char temp[32];

  for (i = 0; i < pipeline->_rescount; i++) {
    if (max_cycles < res_cycles[i])
      max_cycles = res_cycles[i];
    templen = sprintf(temp, "%d", res_cycles[i]);
    if (cyclelen < templen)
      cyclelen = templen;
    commentlen += (int)strlen(pipeline->_reslist.name(i));
  }

  templen = 1 + commentlen + (cyclelen + 8) * pipeline->_rescount;

  // Allocate space for the resource list
  char * resource_cycles = new char [templen];

  templen = 0;

  for (i = 0; i < pipeline->_rescount; i++) {
    templen += sprintf(&resource_cycles[templen], " %*d%c // %s\n",
      cyclelen, res_cycles[i], (i < pipeline->_rescount-1) ? ',' : ' ', pipeline->_reslist.name(i));
  }

  // See if the same string is in the table
  int ndx = pipeline_res_cycles.index(resource_cycles);

  // No, add it to the table
  if (ndx < 0) {
    pipeline_res_cycles.addName(resource_cycles);
    ndx = pipeline_res_cycles.index(resource_cycles);

    fprintf(fp_cpp, "static const uint pipeline_res_cycles_%03d[%d] = {\n%s};\n\n",
      ndx+1, pipeline->_rescount, resource_cycles);
  }
  else
    delete [] resource_cycles;

  delete [] res_cycles;

  return (ndx);
}

//typedef unsigned long long uint64_t;

// Compute an index for an array in the pipeline_res_mask_NNN arrays
static int pipeline_res_mask_initializer(
  FILE *fp_cpp,
  PipelineForm *pipeline,
  NameList &pipeline_res_mask,
  NameList &pipeline_res_args,
  PipeClassForm *pipeclass)
{
  const PipeClassResourceForm *piperesource;
  const uint rescount      = pipeline->_rescount;
  const uint maxcycleused  = pipeline->_maxcycleused;
  const uint cyclemasksize = (maxcycleused + 31) >> 5;

  int i, j;
  uint element_count = 0;
  uint *res_mask = new uint [cyclemasksize];
  uint resources_used             = 0;
  uint resources_used_exclusively = 0;

  for (pipeclass->_resUsage.reset();
       (piperesource = (const PipeClassResourceForm*)pipeclass->_resUsage.iter()) != NULL; ) {
    element_count++;
  }

  // Pre-compute the string length
  int templen;
  int commentlen = 0;
  int max_cycles = 0;

  int cyclelen = ((maxcycleused + 3) >> 2);
  int masklen = (rescount + 3) >> 2;

  int cycledigit = 0;
  for (i = maxcycleused; i > 0; i /= 10)
    cycledigit++;

  int maskdigit = 0;
  for (i = rescount; i > 0; i /= 10)
    maskdigit++;

  static const char* pipeline_use_cycle_mask = "Pipeline_Use_Cycle_Mask";
  static const char* pipeline_use_element    = "Pipeline_Use_Element";

  templen = 1 +
    (int)(strlen(pipeline_use_cycle_mask) + (int)strlen(pipeline_use_element) +
     (cyclemasksize * 12) + masklen + (cycledigit * 2) + 30) * element_count;

  // Allocate space for the resource list
  char * resource_mask = new char [templen];
  char * last_comma = NULL;

  templen = 0;

  for (pipeclass->_resUsage.reset();
       (piperesource = (const PipeClassResourceForm*)pipeclass->_resUsage.iter()) != NULL; ) {
    int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask();

    if (!used_mask) {
      fprintf(stderr, "*** used_mask is 0 ***\n");
    }

    resources_used |= used_mask;

    uint lb, ub;

    for (lb =  0; (used_mask & (1 << lb)) == 0; lb++);
    for (ub = 31; (used_mask & (1 << ub)) == 0; ub--);

    if (lb == ub) {
      resources_used_exclusively |= used_mask;
    }

    int formatlen =
      sprintf(&resource_mask[templen], " %s(0x%0*x, %*d, %*d, %s %s(",
        pipeline_use_element,
        masklen, used_mask,
        cycledigit, lb, cycledigit, ub,
        ((used_mask & (used_mask-1)) != 0) ? "true, " : "false,",
        pipeline_use_cycle_mask);

    templen += formatlen;

    memset(res_mask, 0, cyclemasksize * sizeof(uint));

    int cycles = piperesource->_cycles;
    uint stage          = pipeline->_stages.index(piperesource->_stage);
    if ((uint)NameList::Not_in_list == stage) {
      fprintf(stderr,
              "pipeline_res_mask_initializer: "
              "semantic error: "
              "pipeline stage undeclared: %s\n",
              piperesource->_stage);
      exit(1);
    }
    uint upper_limit    = stage + cycles - 1;
    uint lower_limit    = stage - 1;
    uint upper_idx      = upper_limit >> 5;
    uint lower_idx      = lower_limit >> 5;
    uint upper_position = upper_limit & 0x1f;
    uint lower_position = lower_limit & 0x1f;

    uint mask = (((uint)1) << upper_position) - 1;

    while (upper_idx > lower_idx) {
      res_mask[upper_idx--] |= mask;
      mask = (uint)-1;
    }

    mask -= (((uint)1) << lower_position) - 1;
    res_mask[upper_idx] |= mask;

    for (j = cyclemasksize-1; j >= 0; j--) {
      formatlen =
        sprintf(&resource_mask[templen], "0x%08x%s", res_mask[j], j > 0 ? ", " : "");
      templen += formatlen;
    }

    resource_mask[templen++] = ')';
    resource_mask[templen++] = ')';
    last_comma = &resource_mask[templen];
    resource_mask[templen++] = ',';
    resource_mask[templen++] = '\n';
  }

  resource_mask[templen] = 0;
  if (last_comma) {
    last_comma[0] = ' ';
  }

  // See if the same string is in the table
  int ndx = pipeline_res_mask.index(resource_mask);

  // No, add it to the table
  if (ndx < 0) {
    pipeline_res_mask.addName(resource_mask);
    ndx = pipeline_res_mask.index(resource_mask);

    if (strlen(resource_mask) > 0)
      fprintf(fp_cpp, "static const Pipeline_Use_Element pipeline_res_mask_%03d[%d] = {\n%s};\n\n",
        ndx+1, element_count, resource_mask);

    // "0x012345678, 0x012345678, 4294967295"
    char* args = new char [36 + 1];

    int printed = sprintf(args, "0x%x, 0x%x, %u",
      resources_used, resources_used_exclusively, element_count);
    assert(printed <= 36, "overflow");

    pipeline_res_args.addName(args);
  }
  else {
    delete [] resource_mask;
  }

  delete [] res_mask;
//delete [] res_masks;

  return (ndx);
}

void ArchDesc::build_pipe_classes(FILE *fp_cpp) {
  const char *classname;
  const char *resourcename;
  int resourcenamelen = 0;
  NameList pipeline_reads;
  NameList pipeline_res_stages;
  NameList pipeline_res_cycles;
  NameList pipeline_res_masks;
  NameList pipeline_res_args;
  const int default_latency = 1;
  const int non_operand_latency = 0;
  const int node_latency = 0;

  if (!_pipeline) {
    fprintf(fp_cpp, "uint Node::latency(uint i) const {\n");
    fprintf(fp_cpp, " // assert(false, \"pipeline functionality is not defined\");\n");
    fprintf(fp_cpp, " return %d;\n", non_operand_latency);
    fprintf(fp_cpp, "}\n");
    return;
  }

  fprintf(fp_cpp, "\n");
  fprintf(fp_cpp, "//------------------Pipeline Methods-----------------------------------------\n");
  fprintf(fp_cpp, "#ifndef PRODUCT\n");
  fprintf(fp_cpp, "const char * Pipeline::stageName(uint s) {\n");
  fprintf(fp_cpp, " static const char * const _stage_names[] = {\n");
  fprintf(fp_cpp, " \"undefined\"");

  for (int s = 0; s < _pipeline->_stagecnt; s++)
    fprintf(fp_cpp, ", \"%s\"", _pipeline->_stages.name(s));

  fprintf(fp_cpp, "\n };\n\n");
  fprintf(fp_cpp, " return (s <= %d ? _stage_names[s] : \"???\");\n",
    _pipeline->_stagecnt);
  fprintf(fp_cpp, "}\n");
  fprintf(fp_cpp, "#endif\n\n");

  fprintf(fp_cpp, "uint Pipeline::functional_unit_latency(uint start, const Pipeline *pred) const {\n");
  fprintf(fp_cpp, " // See if the functional units overlap\n");
#if 0
  fprintf(fp_cpp, "\n#ifndef PRODUCT\n");
  fprintf(fp_cpp, " if (TraceOptoOutput) {\n");
  fprintf(fp_cpp, " tty->print(\"#   functional_unit_latency: start == %%d, this->exclusively == 0x%%03x, pred->exclusively == 0x%%03x\\n\", start, resourcesUsedExclusively(), pred->resourcesUsedExclusively());\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, "#endif\n\n");
#endif
  fprintf(fp_cpp, " uint mask = resourcesUsedExclusively() & pred->resourcesUsedExclusively();\n");
  fprintf(fp_cpp, " if (mask == 0)\n return (start);\n\n");
#if 0
  fprintf(fp_cpp, "\n#ifndef PRODUCT\n");
  fprintf(fp_cpp, " if (TraceOptoOutput) {\n");
  fprintf(fp_cpp, " tty->print(\"#   functional_unit_latency: mask == 0x%%x\\n\", mask);\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, "#endif\n\n");
#endif
  fprintf(fp_cpp, " for (uint i = 0; i < pred->resourceUseCount(); i++) {\n");
  fprintf(fp_cpp, " const Pipeline_Use_Element *predUse = pred->resourceUseElement(i);\n");
  fprintf(fp_cpp, " if (predUse->multiple())\n");
  fprintf(fp_cpp, " continue;\n\n");
  fprintf(fp_cpp, " for (uint j = 0; j < resourceUseCount(); j++) {\n");
  fprintf(fp_cpp, " const Pipeline_Use_Element *currUse = resourceUseElement(j);\n");
  fprintf(fp_cpp, " if (currUse->multiple())\n");
  fprintf(fp_cpp, " continue;\n\n");
  fprintf(fp_cpp, " if (predUse->used() & currUse->used()) {\n");
  fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask x = predUse->mask();\n");
  fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask y = currUse->mask();\n\n");
  fprintf(fp_cpp, " for ( y <<= start; x.overlaps(y); start++ )\n");
  fprintf(fp_cpp, " y <<= 1;\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n\n");
  fprintf(fp_cpp, " // There is the potential for overlap\n");
  fprintf(fp_cpp, " return (start);\n");
  fprintf(fp_cpp, "}\n\n");
  fprintf(fp_cpp, "// The following two routines assume that the root Pipeline_Use entity\n");
  fprintf(fp_cpp, "// consists of exactly 1 element for each functional unit\n");
  fprintf(fp_cpp, "// start is relative to the current cycle; used for latency-based info\n");
  fprintf(fp_cpp, "uint Pipeline_Use::full_latency(uint delay, const Pipeline_Use &pred) const {\n"span>);
  fprintf(fp_cpp, " for (uint i = 0; i < pred._count; i++) {\n");
  fprintf(fp_cpp, " const Pipeline_Use_Element *predUse = pred.element(i);\n");
  fprintf(fp_cpp, " if (predUse->_multiple) {\n");
  fprintf(fp_cpp, " uint min_delay = %d;\n",
    _pipeline->_maxcycleused+1);
  fprintf(fp_cpp, " // Multiple possible functional units, choose first unused one\n");
  fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");
  fprintf(fp_cpp, " const Pipeline_Use_Element *currUse = element(j);\n");
  fprintf(fp_cpp, " uint curr_delay = delay;\n");
  fprintf(fp_cpp, " if (predUse->_used & currUse->_used) {\n");
  fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask x = predUse->_mask;\n");
  fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask y = currUse->_mask;\n\n");
  fprintf(fp_cpp, " for ( y <<= curr_delay; x.overlaps(y); curr_delay++ )\n");
  fprintf(fp_cpp, " y <<= 1;\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " if (min_delay > curr_delay)\n min_delay = curr_delay;\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " if (delay < min_delay)\n delay = min_delay;\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " else {\n");
  fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");
  fprintf(fp_cpp, " const Pipeline_Use_Element *currUse = element(j);\n");
  fprintf(fp_cpp, " if (predUse->_used & currUse->_used) {\n");
  fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask x = predUse->_mask;\n");
  fprintf(fp_cpp, " Pipeline_Use_Cycle_Mask y = currUse->_mask;\n\n");
  fprintf(fp_cpp, " for ( y <<= delay; x.overlaps(y); delay++ )\n");
  fprintf(fp_cpp, " y <<= 1;\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n\n");
  fprintf(fp_cpp, " return (delay);\n");
  fprintf(fp_cpp, "}\n\n");
  fprintf(fp_cpp, "void Pipeline_Use::add_usage(const Pipeline_Use &pred) {\n");
  fprintf(fp_cpp, " for (uint i = 0; i < pred._count; i++) {\n");
  fprintf(fp_cpp, " const Pipeline_Use_Element *predUse = pred.element(i);\n");
  fprintf(fp_cpp, " if (predUse->_multiple) {\n");
  fprintf(fp_cpp, " // Multiple possible functional units, choose first unused one\n");
  fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");
  fprintf(fp_cpp, " Pipeline_Use_Element *currUse = element(j);\n");
  fprintf(fp_cpp, " if ( !predUse->_mask.overlaps(currUse->_mask) ) {\n");
  fprintf(fp_cpp, " currUse->_used |= (1 << j);\n");
  fprintf(fp_cpp, " _resources_used |= (1 << j);\n");
  fprintf(fp_cpp, " currUse->_mask.Or(predUse->_mask);\n");
  fprintf(fp_cpp, " break;\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " else {\n");
  fprintf(fp_cpp, " for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");
  fprintf(fp_cpp, " Pipeline_Use_Element *currUse = element(j);\n");
  fprintf(fp_cpp, " currUse->_used |= (1 << j);\n");
  fprintf(fp_cpp, " _resources_used |= (1 << j);\n");
  fprintf(fp_cpp, " currUse->_mask.Or(predUse->_mask);\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, "}\n\n");

  fprintf(fp_cpp, "uint Pipeline::operand_latency(uint opnd, const Pipeline *pred) const {\n");
  fprintf(fp_cpp, " int const default_latency = 1;\n");
  fprintf(fp_cpp, "\n");
#if 0
  fprintf(fp_cpp, "#ifndef PRODUCT\n");
  fprintf(fp_cpp, " if (TraceOptoOutput) {\n");
  fprintf(fp_cpp, " tty->print(\"#   operand_latency(%%d), _read_stage_count = %%d\\n\", opnd, _read_stage_count);\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, "#endif\n\n");
#endif
  fprintf(fp_cpp, " assert(this, \"NULL pipeline info\");\n");
  fprintf(fp_cpp, " assert(pred, \"NULL predecessor pipline info\");\n\n");
  fprintf(fp_cpp, " if (pred->hasFixedLatency())\n return (pred->fixedLatency());\n\n");
  fprintf(fp_cpp, " // If this is not an operand, then assume a dependence with 0 latency\n");
  fprintf(fp_cpp, " if (opnd > _read_stage_count)\n return (0);\n\n");
  fprintf(fp_cpp, " uint writeStage = pred->_write_stage;\n");
  fprintf(fp_cpp, " uint readStage = _read_stages[opnd-1];\n");
#if 0
  fprintf(fp_cpp, "\n#ifndef PRODUCT\n");
  fprintf(fp_cpp, " if (TraceOptoOutput) {\n");
  fprintf(fp_cpp, " tty->print(\"#   operand_latency: writeStage=%%s readStage=%%s, opnd=%%d\\n\", stageName(writeStage), stageName(readStage), opnd);\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, "#endif\n\n");
#endif
  fprintf(fp_cpp, "\n");
  fprintf(fp_cpp, " if (writeStage == stage_undefined || readStage == stage_undefined)\n");
  fprintf(fp_cpp, " return (default_latency);\n");
  fprintf(fp_cpp, "\n");
  fprintf(fp_cpp, " int delta = writeStage - readStage;\n");
  fprintf(fp_cpp, " if (delta < 0) delta = 0;\n\n");
#if 0
  fprintf(fp_cpp, "\n#ifndef PRODUCT\n");
  fprintf(fp_cpp, " if (TraceOptoOutput) {\n");
  fprintf(fp_cpp, " tty->print(\"operand_latency: delta=%%d\\n\", delta);\n");
  fprintf(fp_cpp, " }\n");
  fprintf(fp_cpp, "#endif\n\n");
#endif
  fprintf(fp_cpp, " return (delta);\n");
  fprintf(fp_cpp, "}\n\n");

  if (!_pipeline)
    /* Do Nothing */;

  else if (_pipeline->_maxcycleused <= 32) {
    fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");
    fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask & in2._mask);\n");
    fprintf(fp_cpp, "}\n\n");
    fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");
    fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask | in2._mask);\n");
    fprintf(fp_cpp, "}\n\n");
  }
  else {
    uint l;
    uint masklen = (_pipeline->_maxcycleused + 31) >> 5;
    fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");
    fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(");
    for (l = 1; l <= masklen; l++)
      fprintf(fp_cpp, "in1._mask%d & in2._mask%d%s\n", l, l, l < masklen ? ", " : "");
    fprintf(fp_cpp, ");\n");
    fprintf(fp_cpp, "}\n\n");
    fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n");
    fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(");
    for (l = 1; l <= masklen; l++)
      fprintf(fp_cpp, "in1._mask%d | in2._mask%d%s", l, l, l < masklen ? ", " : "");
    fprintf(fp_cpp, ");\n");
    fprintf(fp_cpp, "}\n\n");
    fprintf(fp_cpp, "void Pipeline_Use_Cycle_Mask::Or(const Pipeline_Use_Cycle_Mask &in2) {\n "span>);
    for (l = 1; l <= masklen; l++)
      fprintf(fp_cpp, " _mask%d |= in2._mask%d;", l, l);
    fprintf(fp_cpp, "\n}\n\n");
  }

  /* Get the length of all the resource names */
  for (_pipeline->_reslist.reset(), resourcenamelen = 0;
       (resourcename = _pipeline->_reslist.iter()) != NULL;
       resourcenamelen += (int)strlen(resourcename));

  // Create the pipeline class description

  fprintf(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");
  fprintf(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");

  fprintf(fp_cpp, "const Pipeline_Use_Element Pipeline_Use::elaborated_elements[%d] = {\n", _pipeline->_rescount);
  for (int i1 = 0; i1 < _pipeline->_rescount; i1++) {
    fprintf(fp_cpp, " Pipeline_Use_Element(0, %d, %d, false, Pipeline_Use_Cycle_Mask(", i1, i1);
    uint masklen = (_pipeline->_maxcycleused + 31) >> 5;
    for (int i2 = masklen-1; i2 >= 0; i2--)
      fprintf(fp_cpp, "0%s", i2 > 0 ? ", " : "");
    fprintf(fp_cpp, "))%s\n", i1 < (_pipeline->_rescount-1) ? "," : "");
  }
  fprintf(fp_cpp, "};\n\n");

  fprintf(fp_cpp, "const Pipeline_Use Pipeline_Use::elaborated_use(0, 0, %d, (Pipeline_Use_Element *)&elaborated_elements[0]);\n\n",
    _pipeline->_rescount);

  for (_pipeline->_classlist.reset(); (classname = _pipeline->_classlist.iter()) != NULL; ) {
    fprintf(fp_cpp, "\n");
    fprintf(fp_cpp, "// Pipeline Class \"%s\"\n", classname);
    PipeClassForm *pipeclass = _pipeline->_classdict[classname]->is_pipeclass();
    int maxWriteStage = -1;
    int maxMoreInstrs = 0;
    int paramcount = 0;
    int i = 0;
    const char *paramname;
    int resource_count = (_pipeline->_rescount + 3) >> 2;

    // Scan the operands, looking for last output stage and number of inputs
    for (pipeclass->_parameters.reset(); (paramname = pipeclass->_parameters.iter()) != NULL; ) {
      const PipeClassOperandForm *pipeopnd =
          (const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
      if (pipeopnd) {
        if (pipeopnd->_iswrite) {
           int stagenum  = _pipeline->_stages.index(pipeopnd->_stage);
           int moreinsts = pipeopnd->_more_instrs;
          if ((maxWriteStage+maxMoreInstrs) < (stagenum+moreinsts)) {
            maxWriteStage = stagenum;
            maxMoreInstrs = moreinsts;
          }
        }
      }

      if (i++ > 0 || (pipeopnd && !pipeopnd->isWrite()))
        paramcount++;
    }

    // Create the list of stages for the operands that are read
    // Note that we will build a NameList to reduce the number of copies

    int pipeline_reads_index = pipeline_reads_initializer(fp_cpp, pipeline_reads, pipeclass);

    int pipeline_res_stages_index = pipeline_res_stages_initializer(
      fp_cpp, _pipeline, pipeline_res_stages, pipeclass);

    int pipeline_res_cycles_index = pipeline_res_cycles_initializer(
      fp_cpp, _pipeline, pipeline_res_cycles, pipeclass);

    int pipeline_res_mask_index = pipeline_res_mask_initializer(
      fp_cpp, _pipeline, pipeline_res_masks, pipeline_res_args, pipeclass);

#if 0
    // Process the Resources
    const PipeClassResourceForm *piperesource;

    unsigned resources_used = 0;
    unsigned exclusive_resources_used = 0;
    unsigned resource_groups = 0;
    for (pipeclass->_resUsage.reset();
         (piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) {
      int used_mask = _pipeline->_resdict[piperesource->_resource]->is_resource()->mask();
      if (used_mask)
        resource_groups++;
      resources_used |= used_mask;
      if ((used_mask & (used_mask-1)) == 0)
        exclusive_resources_used |= used_mask;
    }

    if (resource_groups > 0) {
      fprintf(fp_cpp, "static const uint pipeline_res_or_masks_%03d[%d] = {",
        pipeclass->_num, resource_groups);
      for (pipeclass->_resUsage.reset(), i = 1;
           (piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL;
           i++ ) {
        int used_mask = _pipeline->_resdict[piperesource->_resource]->is_resource()->mask();
        if (used_mask) {
          fprintf(fp_cpp, " 0x%0*x%c", resource_count, used_mask, i < (int)resource_groups ? ',' : ' ');
        }
      }
      fprintf(fp_cpp, "};\n\n");
    }
#endif

    // Create the pipeline class description
    fprintf(fp_cpp, "static const Pipeline pipeline_class_%03d(",
      pipeclass->_num);
    if (maxWriteStage < 0)
      fprintf(fp_cpp, "(uint)stage_undefined");
    else if (maxMoreInstrs == 0)
      fprintf(fp_cpp, "(uint)stage_%s", _pipeline->_stages.name(maxWriteStage));
    else
      fprintf(fp_cpp, "((uint)stage_%s)+%d", _pipeline->_stages.name(maxWriteStage), maxMoreInstrs);
    fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s, %s,\n",
      paramcount,
      pipeclass->hasFixedLatency() ? "true" : "false",
      pipeclass->fixedLatency(),
      pipeclass->InstructionCount(),
      pipeclass->hasBranchDelay() ? "true" : "false",
      pipeclass->hasMultipleBundles() ? "true" : "false",
      pipeclass->forceSerialization() ? "true" : "false",
      pipeclass->mayHaveNoCode() ? "true" : "false" );
    if (paramcount > 0) {
      fprintf(fp_cpp, "\n (enum machPipelineStages * const) pipeline_reads_%03d,\n ",
        pipeline_reads_index+1);
    }
    else
      fprintf(fp_cpp, " NULL,");
    fprintf(fp_cpp, " (enum machPipelineStages * const) pipeline_res_stages_%03d,\n",
      pipeline_res_stages_index+1);
    fprintf(fp_cpp, " (uint * const) pipeline_res_cycles_%03d,\n",
      pipeline_res_cycles_index+1);
    fprintf(fp_cpp, " Pipeline_Use(%s, (Pipeline_Use_Element *)",
      pipeline_res_args.name(pipeline_res_mask_index));
    if (strlen(pipeline_res_masks.name(pipeline_res_mask_index)) > 0)
      fprintf(fp_cpp, "&pipeline_res_mask_%03d[0]",
        pipeline_res_mask_index+1);
    else
      fprintf(fp_cpp, "NULL");
    fprintf(fp_cpp, "));\n");
  }

  // Generate the Node::latency method if _pipeline defined
  fprintf(fp_cpp, "\n");
  fprintf(fp_cpp, "//------------------Inter-Instruction Latency--------------------------------\n");
  fprintf(fp_cpp, "uint Node::latency(uint i) {\n");
  if (_pipeline) {
#if 0
    fprintf(fp_cpp, "#ifndef PRODUCT\n");
    fprintf(fp_cpp, " if (TraceOptoOutput) {\n");
    fprintf(fp_cpp, " tty->print(\"%%4d->latency(%%d)\\n\", _idx, i);\n");
    fprintf(fp_cpp, " }\n");
    fprintf(fp_cpp, "#endif\n");
#endif
    fprintf(fp_cpp, " uint j;\n");
    fprintf(fp_cpp, " // verify in legal range for inputs\n");
    fprintf(fp_cpp, " assert(i < len(), \"index not in range\");\n\n");
    fprintf(fp_cpp, " // verify input is not null\n");
    fprintf(fp_cpp, " Node *pred = in(i);\n");
    fprintf(fp_cpp, " if (!pred)\n return %d;\n\n",
      non_operand_latency);
    fprintf(fp_cpp, " if (pred->is_Proj())\n pred = pred->in(0);\n\n");
    fprintf(fp_cpp, " // if either node does not have pipeline info, use default\n");
    fprintf(fp_cpp, " const Pipeline *predpipe = pred->pipeline();\n");
    fprintf(fp_cpp, " assert(predpipe, \"no predecessor pipeline info\");\n\n");
    fprintf(fp_cpp, " if (predpipe->hasFixedLatency())\n return predpipe->fixedLatency();\n\n");
    fprintf(fp_cpp, " const Pipeline *currpipe = pipeline();\n");
    fprintf(fp_cpp, " assert(currpipe, \"no pipeline info\");\n\n");
    fprintf(fp_cpp, " if (!is_Mach())\n return %d;\n\n",
      node_latency);
    fprintf(fp_cpp, " const MachNode *m = as_Mach();\n");
    fprintf(fp_cpp, " j = m->oper_input_base();\n");
    fprintf(fp_cpp, " if (i < j)\n return currpipe->functional_unit_latency(%d, predpipe);\n\n",
      non_operand_latency);
    fprintf(fp_cpp, " // determine which operand this is in\n");
    fprintf(fp_cpp, " uint n = m->num_opnds();\n");
    fprintf(fp_cpp, " int delta = %d;\n\n",
      non_operand_latency);
    fprintf(fp_cpp, " uint k;\n");
    fprintf(fp_cpp, " for (k = 1; k < n; k++) {\n");
    fprintf(fp_cpp, " j += m->_opnds[k]->num_edges();\n");
    fprintf(fp_cpp, " if (i < j)\n");
    fprintf(fp_cpp, " break;\n");
    fprintf(fp_cpp, " }\n");
    fprintf(fp_cpp, " if (k < n)\n");
    fprintf(fp_cpp, " delta = currpipe->operand_latency(k,predpipe);\n\n");
    fprintf(fp_cpp, " return currpipe->functional_unit_latency(delta, predpipe);\n");
  }
  else {
    fprintf(fp_cpp, " // assert(false, \"pipeline functionality is not defined\");\n");
    fprintf(fp_cpp, " return %d;\n",
      non_operand_latency);
  }
  fprintf(fp_cpp, "}\n\n");

  // Output the list of nop nodes
  fprintf(fp_cpp, "// Descriptions for emitting different functional unit nops\n");
  const char *nop;
  int nopcnt = 0;
  for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; nopcnt++ );

  fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d]) {\n", nopcnt);
  int i = 0;
  for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; i++ ) {
    fprintf(fp_cpp, " nop_list[%d] = (MachNode *) new %sNode();\n", i, nop);
  }
  fprintf(fp_cpp, "};\n\n");
  fprintf(fp_cpp, "#ifndef PRODUCT\n");
  fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n");
  fprintf(fp_cpp, " static const char * bundle_flags[] = {\n");
  fprintf(fp_cpp, " \"\",\n");
  fprintf(fp_cpp, " \"use nop delay\",\n");
  fprintf(fp_cpp, " \"use unconditional delay\",\n");
  fprintf(fp_cpp, " \"use conditional delay\",\n");
  fprintf(fp_cpp, " \"used in conditional delay\",\n");
  fprintf(fp_cpp, " \"used in unconditional delay\",\n");
  fprintf(fp_cpp, " \"used in all conditional delays\",\n");
  fprintf(fp_cpp, " };\n\n");

  fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount);
  for (i = 0; i < _pipeline->_rescount; i++)
    fprintf(fp_cpp, " \"%s\"%c", _pipeline->_reslist.name(i), i < _pipeline->_rescount-1 ? ',' ' ');
  fprintf(fp_cpp, "};\n\n");

  // See if the same string is in the table
  fprintf(fp_cpp, " bool needs_comma = false;\n\n");
  fprintf(fp_cpp, " if (_flags) {\n");
  fprintf(fp_cpp, " st->print(\"%%s\", bundle_flags[_flags]);\n");
  fprintf(fp_cpp, " needs_comma = true;\n");
  fprintf(fp_cpp, " };\n");
  fprintf(fp_cpp, " if (instr_count()) {\n");
  fprintf(fp_cpp, " st->print(\"%%s%%d instr%%s\", needs_comma ? \", \" : \"\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n");
  fprintf(fp_cpp, " needs_comma = true;\n");
  fprintf(fp_cpp, " };\n");
  fprintf(fp_cpp, " uint r = resources_used();\n");
  fprintf(fp_cpp, " if (r) {\n");
  fprintf(fp_cpp, " st->print(\"%%sresource%%s:\", needs_comma ? \", \" : \"\", (r & (r-1)) != 0 ? \"s\" : \"\");\n");
  fprintf(fp_cpp, " for (uint i = 0; i < %d; i++)\n", _pipeline->_rescount);
  fprintf(fp_cpp, " if ((r & (1 << i)) != 0)\n");
  fprintf(fp_cpp, " st->print(\" %%s\", resource_names[i]);\n");
  fprintf(fp_cpp, " needs_comma = true;\n");
  fprintf(fp_cpp, " };\n");
  fprintf(fp_cpp, " st->print(\"\\n\");\n");
  fprintf(fp_cpp, "}\n");
  fprintf(fp_cpp, "#endif\n");
}

// ---------------------------------------------------------------------------
//------------------------------Utilities to build Instruction Classes--------
// ---------------------------------------------------------------------------

static void defineOut_RegMask(FILE *fp, const char *node, const char *regMask) {
  fprintf(fp,"const RegMask &%sNode::out_RegMask() const { return (%s); }\n",
          node, regMask);
}

static void print_block_index(FILE *fp, int inst_position) {
  assert( inst_position >= 0, "Instruction number less than zero");
  fprintf(fp, "block_index");
  if( inst_position != 0 ) {
    fprintf(fp, " - %d", inst_position);
  }
}

// Scan the peepmatch and output a test for each instruction
static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) {
  int         parent        = -1;
  int         inst_position = 0;
  const char* inst_name     = NULL;
  int         input         = 0;
  fprintf(fp, " // Check instruction sub-tree\n");
  pmatch->reset();
  for( pmatch->next_instruction( parent, inst_position, inst_name, input );
       inst_name != NULL;
       pmatch->next_instruction( parent, inst_position, inst_name, input ) ) {
    // If this is not a placeholder
    if( ! pmatch->is_placeholder() ) {
      // Define temporaries 'inst#', based on parent and parent's input index
      if( parent != -1 ) {                // root was initialized
        fprintf(fp, " // Identify previous instruction if inside this block\n");
        fprintf(fp, " if( ");
        print_block_index(fp, inst_position);
        fprintf(fp, " > 0 ) {\n Node *n = block->get_node(");
        print_block_index(fp, inst_position);
        fprintf(fp, ");\n inst%d = (n->is_Mach()) ? ", inst_position);
        fprintf(fp, "n->as_Mach() : NULL;\n }\n");
      }

      // When not the root
      // Test we have the correct instruction by comparing the rule.
      if( parent != -1 ) {
        fprintf(fp, " matches = matches && (inst%d != NULL) && (inst%d->rule() == %s_rule);\n",
                inst_position, inst_position, inst_name);
      }
    } else {
      // Check that user did not try to constrain a placeholder
      assert( ! pconstraint->constrains_instruction(inst_position),
              "fatal(): Can not constrain a placeholder instruction");
    }
  }
}

// Build mapping for register indices, num_edges to input
static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMatch *pmatch ) {
  int         parent        = -1;
  int         inst_position = 0;
  const char* inst_name     = NULL;
  int         input         = 0;
  fprintf(fp, " // Build map to register info\n");
  pmatch->reset();
  for( pmatch->next_instruction( parent, inst_position, inst_name, input );
       inst_name != NULL;
       pmatch->next_instruction( parent, inst_position, inst_name, input ) ) {
    // If this is not a placeholder
    if( ! pmatch->is_placeholder() ) {
      // Define temporaries 'inst#', based on self's inst_position
      InstructForm *inst = globals[inst_name]->is_instruction();
      if( inst != NULL ) {
        char inst_prefix[]  = "instXXXX_";
        sprintf(inst_prefix, "inst%d_",   inst_position);
        char receiver[]     = "instXXXX->";
        sprintf(receiver,    "inst%d->", inst_position);
        inst->index_temps( fp, globals, inst_prefix, receiver );
      }
    }
  }
}

// Generate tests for the constraints
static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch, PeepConstraint *pconstraint) {
  fprintf(fp, "\n");
  fprintf(fp, " // Check constraints on sub-tree-leaves\n");

  // Build mapping from num_edges to local variables
  build_instruction_index_mapping( fp, globals, pmatch );

  // Build constraint tests
  if( pconstraint != NULL ) {
    fprintf(fp, " matches = matches &&");
    bool   first_constraint = true;
    while( pconstraint != NULL ) {
      // indentation and connecting '&&'
      const char *indentation = " ";
      fprintf(fp, "\n%s%s", indentation, (!first_constraint ? "&& " : " "));

      // Only have '==' relation implemented
      if( strcmp(pconstraint->_relation,"==") != 0 ) {
        assert( false"Unimplemented()" );
      }

      // LEFT
      int left_index       = pconstraint->_left_inst;
      const char *left_op  = pconstraint->_left_op;
      // Access info on the instructions whose operands are compared
      InstructForm *inst_left = globals[pmatch->instruction_name(left_index)]->is_instruction();
      assert( inst_left, "Parser should guaranty this is an instruction");
      int left_op_base  = inst_left->oper_input_base(globals);
      // Access info on the operands being compared
      int left_op_index  = inst_left->operand_position(left_op, Component::USE);
      if( left_op_index == -1 ) {
        left_op_index = inst_left->operand_position(left_op, Component::DEF);
        if( left_op_index == -1 ) {
          left_op_index = inst_left->operand_position(left_op, Component::USE_DEF);
        }
      }
      assert( left_op_index  != NameList::Not_in_list, "Did not find operand in instruction");
      ComponentList components_left = inst_left->_components;
      const char *left_comp_type = components_left.at(left_op_index)->_type;
      OpClassForm *left_opclass = globals[left_comp_type]->is_opclass();
      Form::InterfaceType left_interface_type = left_opclass->interface_type(globals);


      // RIGHT
      int right_op_index = -1;
      int right_index      = pconstraint->_right_inst;
      const char *right_op = pconstraint->_right_op;
      if( right_index != -1 ) { // Match operand
        // Access info on the instructions whose operands are compared
        InstructForm *inst_right = globals[pmatch->instruction_name(right_index)]->is_instruction();
        assert( inst_right, "Parser should guaranty this is an instruction");
        int right_op_base = inst_right->oper_input_base(globals);
        // Access info on the operands being compared
        right_op_index = inst_right->operand_position(right_op, Component::USE);
        if( right_op_index == -1 ) {
          right_op_index = inst_right->operand_position(right_op, Component::DEF);
          if( right_op_index == -1 ) {
            right_op_index = inst_right->operand_position(right_op, Component::USE_DEF);
          }
        }
        assert( right_op_index != NameList::Not_in_list, "Did not find operand in instruction");
        ComponentList components_right = inst_right->_components;
        const char *right_comp_type = components_right.at(right_op_index)->_type;
        OpClassForm *right_opclass = globals[right_comp_type]->is_opclass();
        Form::InterfaceType right_interface_type = right_opclass->interface_type(globals);
        assert( right_interface_type == left_interface_type, "Both must be same interface");

      } else {                  // Else match register
        // assert( false, "should be a register" );
      }

      //
      // Check for equivalence
      //
      // fprintf(fp, "(inst%d->_opnds[%d]->reg(ra_,inst%d%s)  /* %d.%s */ == /* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)",
      //         left_index, left_op_index, left_index, left_reg_index, left_index, left_op
      //         right_index, right_op, right_index, right_op_index, right_index, right_reg_index);
      // fprintf(fp, ")");
      //
      switch( left_interface_type ) {
      case Form::register_interface: {
        // Check that they are allocated to the same register
        // Need parameter for index position if not result operand
        char left_reg_index[] = ",inst4294967295_idx4294967295";
        if( left_op_index != 0 ) {
          // Must have index into operands
          sprintf(left_reg_index,",inst%u_idx%u", (unsigned)left_index, (unsigned)left_op_index);
        } else {
          strcpy(left_reg_index, "");
        }
        fprintf(fp, "(inst%d->_opnds[%d]->reg(ra_,inst%d%s) /* %d.%s */",
                left_index,  left_op_index, left_index, left_reg_index, left_index, left_op );
        fprintf(fp, " == ");

        if( right_index != -1 ) {
          char right_reg_index[] = ",inst4294967295_idx4294967295";
          if( right_op_index != 0 ) {
            // Must have index into operands
            sprintf(right_reg_index,",inst%u_idx%u", (unsigned)right_index, (unsigned)right_op_index);
          } else {
            strcpy(right_reg_index, "");
          }
          fprintf(fp, "/* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)",
                  right_index, right_op, right_index, right_op_index, right_index, right_reg_index );
        } else {
          fprintf(fp, "%s_enc", right_op );
        }
        fprintf(fp,")");
        break;
      }
      case Form::constant_interface: {
        // Compare the '->constant()' values
        fprintf(fp, "(inst%d->_opnds[%d]->constant() /* %d.%s */",
                left_index,  left_op_index,  left_index, left_op );
        fprintf(fp, " == ");
        fprintf(fp, "/* %d.%s */ inst%d->_opnds[%d]->constant())",
                right_index, right_op, right_index, right_op_index );
        break;
      }
      case Form::memory_interface: {
        // Compare 'base', 'index', 'scale', and 'disp'
        // base
        fprintf(fp, "( \n");
        fprintf(fp, " (inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d) /* %d.%s$$base */",
          left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );
        fprintf(fp, " == ");
        fprintf(fp, "/* %d.%s$$base */ inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d)) &&\n",
                right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );
        // index
        fprintf(fp, " (inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d) /* %d.%s$$index */",
                left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );
        fprintf(fp, " == ");
        fprintf(fp, "/* %d.%s$$index */ inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d)) &&\n",
                right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );
        // scale
        fprintf(fp, " (inst%d->_opnds[%d]->scale() /* %d.%s$$scale */",
                left_index,  left_op_index,  left_index, left_op );
        fprintf(fp, " == ");
        fprintf(fp, "/* %d.%s$$scale */ inst%d->_opnds[%d]->scale()) &&\n",
                right_index, right_op, right_index, right_op_index );
        // disp
        fprintf(fp, " (inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d) /* %d.%s$$disp */",
                left_index, left_op_index, left_index, left_index, left_op_index, left_index, left_op );
        fprintf(fp, " == ");
        fprintf(fp, "/* %d.%s$$disp */ inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d))\n",
                right_index, right_op, right_index, right_op_index, right_index, right_index, right_op_index );
        fprintf(fp, ") \n");
        break;
      }
      case Form::conditional_interface: {
        // Compare the condition code being tested
        assert( false"Unimplemented()" );
        break;
      }
      default: {
        assert( false"ShouldNotReachHere()" );
        break;
      }
      }

      // Advance to next constraint
      pconstraint = pconstraint->next();
      first_constraint = false;
    }

    fprintf(fp, ";\n");
  }
}

// // EXPERIMENTAL -- TEMPORARY code
// static Form::DataType get_operand_type(FormDict &globals, InstructForm *instr, const char *op_name ) {
//   int op_index = instr->operand_position(op_name, Component::USE);
//   if( op_index == -1 ) {
//     op_index = instr->operand_position(op_name, Component::DEF);
//     if( op_index == -1 ) {
//       op_index = instr->operand_position(op_name, Component::USE_DEF);
//     }
//   }
//   assert( op_index != NameList::Not_in_list, "Did not find operand in instruction");
//
//   ComponentList components_right = instr->_components;
//   char *right_comp_type = components_right.at(op_index)->_type;
//   OpClassForm *right_opclass = globals[right_comp_type]->is_opclass();
//   Form::InterfaceType  right_interface_type = right_opclass->interface_type(globals);
//
//   return;
// }

// Construct the new sub-tree
static void generate_peepreplace( FILE *fp, FormDict &globals, int peephole_number, PeepMatch *pmatch,
                                  PeepConstraint *pconstraint, PeepReplace *preplace, int max_position ) {
  fprintf(fp, " // IF instructions and constraints matched\n");
  fprintf(fp, " if( matches ) {\n");
  fprintf(fp, " // generate the new sub-tree\n");
  fprintf(fp, " assert( true, \"Debug stopping point\");\n");
  if( preplace != NULL ) {
    // Get the root of the new sub-tree
    const char *root_inst = NULL;
    preplace->next_instruction(root_inst);
    InstructForm *root_form = globals[root_inst]->is_instruction();
    assert( root_form != NULL, "Replacement instruction was not previously defined");
    fprintf(fp, " %sNode *root = new %sNode();\n", root_inst, root_inst);

    int         inst_num;
    const char *op_name;
    int         opnds_index = 0;            // define result operand
    // Then install the use-operands for the new sub-tree
    // preplace->reset();             // reset breaks iteration
    for( preplace->next_operand( inst_num, op_name );
         op_name != NULL;
         preplace->next_operand( inst_num, op_name ) ) {
      InstructForm *inst_form;
      inst_form  = globals[pmatch->instruction_name(inst_num)]->is_instruction();
      assert( inst_form, "Parser should guaranty this is an instruction");
      int inst_op_num = inst_form->operand_position(op_name, Component::USE);
      if( inst_op_num == NameList::Not_in_list )
        inst_op_num = inst_form->operand_position(op_name, Component::USE_DEF);
      assert( inst_op_num != NameList::Not_in_list, "Did not find operand as USE");
      // find the name of the OperandForm from the local name
      const Form *form   = inst_form->_localNames[op_name];
      OperandForm  *op_form = form->is_operand();
      if( opnds_index == 0 ) {
        // Initial setup of new instruction
        fprintf(fp, " // ----- Initial setup -----\n");
        //
        // Add control edge for this node
        fprintf(fp, " root->add_req(_in[0]); // control edge\n");
        // Add unmatched edges from root of match tree
        int op_base = root_form->oper_input_base(globals);
        forint unmatched_edge = 1; unmatched_edge < op_base; ++unmatched_edge ) {
          fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",
                                          inst_num, unmatched_edge);
        }
        // If new instruction captures bottom type
        if( root_form->captures_bottom_type(globals) ) {
          // Get bottom type from instruction whose result we are replacing
          fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);
        }
        // Define result register and result operand
        fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num);
        fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num);
        fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(); // result\n", inst_num);
        fprintf(fp, " // ----- Done with initial setup -----\n");
      } else {
        if( (op_form == NULL) || (op_form->is_base_constant(globals) == Form::none) ) {
          // Do not have ideal edges for constants after matching
          fprintf(fp, " for( unsigned x%d = inst%d_idx%d; x%d < inst%d_idx%d; x%d++ )\n",
                  inst_op_num, inst_num, inst_op_num,
                  inst_op_num, inst_num, inst_op_num+1, inst_op_num );
          fprintf(fp, " root->add_req( inst%d->in(x%d) );\n",
                  inst_num, inst_op_num );
        } else {
          fprintf(fp, " // no ideal edge for constants after matching\n");
        }
        fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone();\n",
                opnds_index, inst_num, inst_op_num );
      }
      ++opnds_index;
    }
  }else {
    // Replacing subtree with empty-tree
    assert( false"ShouldNotReachHere();");
  }

  // Set output of the new node
  fprintf(fp, " inst0->replace_by(root);\n");
  // Mark the node as removed because peephole does not remove nodes from the graph
  for (int i = 0; i <= max_position; i++) {
    fprintf(fp, " inst%d->set_removed();\n", i);
    fprintf(fp, " cfg_->map_node_to_block(inst%d, nullptr);\n", i);
  }
  for (int i = 0; i <= max_position; i++) {
    fprintf(fp, " block->remove_node(block_index - %d);\n", i);
  }
  fprintf(fp, " block->insert_node(root, block_index - %d);\n", max_position);
  fprintf(fp, " cfg_->map_node_to_block(root, block);\n");
  // Return the peephole index
  fprintf(fp, " return %d; // return the peephole index;\n", peephole_number);
  fprintf(fp, " }\n");
}


// Define the Peephole method for an instruction node
void ArchDesc::definePeephole(FILE *fp, InstructForm *node) {
  // Generate Peephole function header
  fprintf(fp, "int %sNode::peephole(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_) {\n", node->_ident);
  fprintf(fp, " bool matches = true;\n");

  // Identify the maximum instruction position,
  // generate temporaries that hold current instruction
  //
  //   MachNode  *inst0 = NULL;
  //   ...
  //   MachNode  *instMAX = NULL;
  //
  int max_position = 0;
  Peephole *peep;
  for( peep = node->peepholes(); peep != NULL; peep = peep->next() ) {
    if (peep->procedure() != NULL) {
      continue;
    }
    PeepMatch *pmatch = peep->match();
    assert( pmatch != NULL, "fatal(), missing peepmatch rule");
    if( max_position < pmatch->max_position() )  max_position = pmatch->max_position();
  }
  forint i = 0; i <= max_position; ++i ) {
    if( i == 0 ) {
      fprintf(fp, " MachNode *inst0 = this;\n");
    } else {
      fprintf(fp, " MachNode *inst%d = NULL;\n", i);
    }
  }

  // For each peephole rule in architecture description
  //   Construct a test for the desired instruction sub-tree
  //   then check the constraints
  //   If these match, Generate the new subtree
  for( peep = node->peepholes(); peep != NULL; peep = peep->next() ) {
    int         peephole_number = peep->peephole_number();
    PeepPredicate  *ppredicate  = peep->predicate();
    PeepMatch      *pmatch      = peep->match();
    PeepProcedure  *pprocedure  = peep->procedure();
    PeepConstraint *pconstraint = peep->constraints();
    PeepReplace    *preplace    = peep->replacement();

    // Root of this peephole is the current MachNode
    assert( true// %%name?%% strcmp( node->_ident, pmatch->name(0) ) == 0,
            "root of PeepMatch does not match instruction");

    // Make each peephole rule individually selectable
    fprintf(fp, " if( ((OptoPeepholeAt == -1) || (OptoPeepholeAt==%d)) && ( %s ) ) {\n",
            peephole_number, ppredicate != NULL ? ppredicate->rule() : "true");
    if (pprocedure == NULL) {
      fprintf(fp, " matches = true;\n");
      // Scan the peepmatch and output a test for each instruction
      check_peepmatch_instruction_sequence( fp, pmatch, pconstraint );

      // Check constraints and build replacement inside scope
      fprintf(fp, " // If instruction subtree matches\n");
      fprintf(fp, " if( matches ) {\n");

      // Generate tests for the constraints
      check_peepconstraints( fp, _globalNames, pmatch, pconstraint );

      // Construct the new sub-tree
      generate_peepreplace( fp, _globalNames, peephole_number, pmatch, pconstraint, preplace, max_position );

      // End of scope for this peephole's constraints
      fprintf(fp, " }\n");
    } else {
      const char* replace_inst = NULL;
      preplace->next_instruction(replace_inst);
      // Generate the target instruction
      fprintf(fp, " auto replacing = [](){ return static_cast(new %sNode()); };\n", replace_inst);

      // Call the precedure
      fprintf(fp, " bool replacement = Peephole::%s(block, block_index, cfg_, ra_, replacing", pprocedure->name());

      int         parent        = -1;
      int         inst_position = 0;
      const char* inst_name     = NULL;
      int         input         = 0;
      pmatch->reset();
      for (pmatch->next_instruction(parent, inst_position, inst_name, input);
           inst_name != NULL;
           pmatch->next_instruction(parent, inst_position, inst_name, input)) {
        fprintf(fp, ", %s_rule", inst_name);
      }
      fprintf(fp, ");\n");

      // If substitution succeeded, return the new node
      fprintf(fp, " if (replacement) {\n");
      fprintf(fp, " return %d;\n", peephole_number);
      fprintf(fp, " }\n");
    }

    // Closing brace '}' to make each peephole rule individually selectable
    fprintf(fp, " } // end of peephole rule #%d\n", peephole_number);
    fprintf(fp, "\n");
  }

  fprintf(fp, " return -1; // No peephole rules matched\n");
  fprintf(fp, "}\n");
  fprintf(fp, "\n");
}

// Define the Expand method for an instruction node
void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
  unsigned      cnt  = 0;          // Count nodes we have expand into
  unsigned      i;

  // Generate Expand function header
  fprintf(fp, "MachNode* %sNode::Expand(State* state, Node_List& proj_list, Node* mem) {\n", node->_ident);
  fprintf(fp, " Compile* C = Compile::current();\n");
  // Generate expand code
  if( node->expands() ) {
    const char   *opid;
    int           new_pos, exp_pos;
    const char   *new_id   = NULL;
    const Form   *frm      = NULL;
    InstructForm *new_inst = NULL;
    OperandForm  *new_oper = NULL;
    unsigned      numo     = node->num_opnds() +
                                node->_exprule->_newopers.count();

    // If necessary, generate any operands created in expand rule
    if (node->_exprule->_newopers.count()) {
      for(node->_exprule->_newopers.reset();
          (new_id = node->_exprule->_newopers.iter()) != NULL; cnt++) {
        frm = node->_localNames[new_id];
        assert(frm, "Invalid entry in new operands list of expand rule");
        new_oper = frm->is_operand();
        char *tmp = (char *)node->_exprule->_newopconst[new_id];
        if (tmp == NULL) {
          fprintf(fp," MachOper *op%d = new %sOper();\n",
                  cnt, new_oper->_ident);
        }
        else {
          fprintf(fp," MachOper *op%d = new %sOper(%s);\n",
                  cnt, new_oper->_ident, tmp);
        }
      }
    }
    cnt = 0;
    // Generate the temps to use for DAG building
    for(i = 0; i < numo; i++) {
      if (i < node->num_opnds()) {
        fprintf(fp," MachNode *tmp%d = this;\n", i);
      }
      else {
        fprintf(fp," MachNode *tmp%d = NULL;\n", i);
      }
    }
    // Build mapping from num_edges to local variables
    fprintf(fp," unsigned num0 = 0;\n");
    for( i = 1; i < node->num_opnds(); i++ ) {
      fprintf(fp," unsigned num%d = opnd_array(%d)->num_edges();\n",i,i);
    }

    // Build a mapping from operand index to input edges
    fprintf(fp," unsigned idx0 = oper_input_base();\n");

    // The order in which the memory input is added to a node is very
    // strange.  Store nodes get a memory input before Expand is
    // called and other nodes get it afterwards or before depending on
    // match order so oper_input_base is wrong during expansion.  This
    // code adjusts it so that expansion will work correctly.
    int has_memory_edge = node->_matrule->needs_ideal_memory_edge(_globalNames);
    if (has_memory_edge) {
      fprintf(fp," if (mem == (Node*)1) {\n");
      fprintf(fp," idx0--; // Adjust base because memory edge hasn't been inserted yet\n");
      fprintf(fp," }\n");
    }

    for( i = 0; i < node->num_opnds(); i++ ) {
      fprintf(fp," unsigned idx%d = idx%d + num%d;\n",
              i+1,i,i);
    }

    // Declare variable to hold root of expansion
    fprintf(fp," MachNode *result = NULL;\n");

    // Iterate over the instructions 'node' expands into
    ExpandRule  *expand       = node->_exprule;
    NameAndList *expand_instr = NULL;
    for (expand->reset_instructions();
         (expand_instr = expand->iter_instructions()) != NULL; cnt++) {
      new_id = expand_instr->name();

      InstructForm* expand_instruction = (InstructForm*)globalAD->globalNames()[new_id];

      if (!expand_instruction) {
        globalAD->syntax_err(node->_linenum, "In %s: instruction %s used in expand not declared\n",
                             node->_ident, new_id);
        continue;
      }

      // Build the node for the instruction
      fprintf(fp,"\n %sNode *n%d = new %sNode();\n", new_id, cnt, new_id);
      // Add control edge for this node
      fprintf(fp," n%d->add_req(_in[0]);\n", cnt);
      // Build the operand for the value this node defines.
      Form *form = (Form*)_globalNames[new_id];
      assert(form, "'new_id' must be a defined form name");
      // Grab the InstructForm for the new instruction
      new_inst = form->is_instruction();
      assert(new_inst, "'new_id' must be an instruction name");
      if (node->is_ideal_if() && new_inst->is_ideal_if()) {
        fprintf(fp, " ((MachIfNode*)n%d)->_prob = _prob;\n", cnt);
        fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n", cnt);
      }

      if (node->is_ideal_fastlock() && new_inst->is_ideal_fastlock()) {
        fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n", cnt);
        fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n", cnt);
      }

      // Fill in the bottom_type where requested
      if (node->captures_bottom_type(_globalNames) &&
--> --------------------

--> maximum size reached

--> --------------------

¤ Dauer der Verarbeitung: 0.203 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.


Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff