/* * 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 staticbool is_def(int usedef) { switch(usedef) { case Component::DEF: case Component::USE_DEF: returntrue; break;
} returnfalse;
}
// Define an array containing the machine register names, strings. staticvoid 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(); constchar *comma = (next != NULL) ? "," : " // no trailing comma";
fprintf(fp," \"%s\"%s\n", reg_def->_regname, comma);
}
// Define an array containing the machine register encoding values staticvoid 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(); constchar* register_encode = reg_def->register_encode(); constchar *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 staticvoid 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 (constchar *class_name = NULL; (class_name = registers->_rclasses.iter()) != NULL;) { constchar * 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) { constchar *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) { constchar *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 staticint pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, PipeClassForm *pipeclass)
{ int templen = 1; int paramcount = 0; constchar *paramname;
if (pipeclass->_parameters.count() == 0) return -1;
// Compute an index for an array in the pipeline_res_stages_NNN arrays staticint pipeline_res_stages_initializer(
FILE *fp_cpp,
PipelineForm *pipeline,
NameList &pipeline_res_stages,
PipeClassForm *pipeclass)
{ const PipeClassResourceForm *piperesource; int * res_stages = newint [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;
}
// Compute an index for an array in the pipeline_res_cycles_NNN arrays staticint pipeline_res_cycles_initializer(
FILE *fp_cpp,
PipelineForm *pipeline,
NameList &pipeline_res_cycles,
PipeClassForm *pipeclass)
{ const PipeClassResourceForm *piperesource; int * res_cycles = newint [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));
}
/* Get the length of all the resource names */ for (_pipeline->_reslist.reset(), resourcenamelen = 0;
(resourcename = _pipeline->_reslist.iter()) != NULL;
resourcenamelen += (int)strlen(resourcename));
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; constchar *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;
// 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"); constchar *nop; int nopcnt = 0; for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != NULL; nopcnt++ );
staticvoid 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 staticvoid check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) { int parent = -1; int inst_position = 0; constchar* 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 staticvoid build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMatch *pmatch ) { int parent = -1; int inst_position = 0; constchar* 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 staticvoid 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 );
// Construct the new sub-tree staticvoid 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 constchar *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; constchar *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); for( int 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();
} for( int 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 );
int parent = -1; int inst_position = 0; constchar* 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");
}
// 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;
// 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();
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);
}
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.