output_c.cpp revision 2964
0N/A * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 0N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A// output_c.cpp - Class CPP file output routines for architecture definition 0N/A// Utilities to characterize effect statements 0N/A// Define an array containing the machine register names, strings. 0N/A fprintf(
fp,
"// An array of character pointers to machine register names.\n");
0N/A fprintf(
fp,
"const char *Matcher::regName[REG_COUNT] = {\n");
0N/A // Output the register name for each register in the allocation classes 0N/A // Finish defining enumeration 0N/A fprintf(
fp,
"// An array of character pointers to machine register names.\n");
0N/A fprintf(
fp,
"const VMReg OptoReg::opto2vm[REG_COUNT] = {\n");
0N/A // Finish defining array 0N/A fprintf(
fp,
" OptoReg::Name OptoReg::vm2opto[ConcreteRegisterImpl::number_of_registers];\n");
0N/A// Define an array containing the machine register encoding values 0N/A fprintf(
fp,
"// An array of the machine register encode values\n");
0N/A fprintf(
fp,
"const unsigned char Matcher::_regEncode[REG_COUNT] = {\n");
0N/A // Output the register encoding for each register in the allocation classes 0N/A // Output known constants in hex char format (backward compatibility). 0N/A // Finish defining enumeration 0N/A }
// Done defining array // Output an enumeration of register class names // Output an enumeration of register class names fprintf(
fp,
"// Enumeration of register class names\n");
// Finish defining enumeration // Declare an enumeration of user-defined register classes // and a list of register masks, one for each class. // Build enumeration of user-defined register classes. // Generate a list of register masks, one for each class. fprintf(
fp_hpp,
"// Register masks, one for each register class.\n");
// Generate an enumeration of user-defined register classes // and a list of register masks, one for each class. // Generate a list of register masks, one for each class. fprintf(
fp_cpp,
"// Register masks, one for each register class.\n");
for( i = 0; i <
len-
1; i++ )
for( i = 0; i <
len-
1; i++ )
// Compute an index for an array in the pipeline_reads_NNN arrays // See if the count is zero // See if the same string is in the table // No, add it to the table fprintf(
fp_cpp,
"static const enum machPipelineStages pipeline_reads_%03d[%d] = {\n%s};\n\n",
// Compute an index for an array in the pipeline_res_stages_NNN arrays // Compute the length needed for the resource list // Allocate space for the resource list // See if the same string is in the table // No, add it to the table fprintf(
fp_cpp,
"static const enum machPipelineStages pipeline_res_stages_%03d[%d] = {\n%s};\n\n",
// Compute an index for an array in the pipeline_res_cycles_NNN arrays // Pre-compute the string length // Allocate space for the resource list // See if the same string is in the table // No, add it to the table fprintf(
fp_cpp,
"static const uint pipeline_res_cycles_%03d[%d] = {\n%s};\n\n",
//typedef unsigned long long uint64_t; // Compute an index for an array in the pipeline_res_mask_NNN arrays // Pre-compute the string length // Allocate space for the resource list // See if the same string is in the table // No, add it to the table fprintf(
fp_cpp,
"static const Pipeline_Use_Element pipeline_res_mask_%03d[%d] = {\n%s};\n\n",
fprintf(
fp_cpp,
" // assert(false, \"pipeline functionality is not defined\");\n");
fprintf(
fp_cpp,
"//------------------Pipeline Methods-----------------------------------------\n");
fprintf(
fp_cpp,
" static const char * const _stage_names[] = {\n");
fprintf(
fp_cpp,
" return (s <= %d ? _stage_names[s] : \"???\");\n",
fprintf(
fp_cpp,
"uint Pipeline::functional_unit_latency(uint start, const Pipeline *pred) const {\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,
" uint mask = resourcesUsedExclusively() & pred->resourcesUsedExclusively();\n");
fprintf(
fp_cpp,
" tty->print(\"# functional_unit_latency: mask == 0x%%x\\n\", mask);\n");
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,
" for (uint j = 0; j < resourceUseCount(); j++) {\n");
fprintf(
fp_cpp,
" const Pipeline_Use_Element *currUse = resourceUseElement(j);\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,
"// 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");
fprintf(
fp_cpp,
" const Pipeline_Use_Element *predUse = pred.element(i);\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,
" const Pipeline_Use_Element *currUse = element(j);\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,
" if (min_delay > curr_delay)\n min_delay = curr_delay;\n");
fprintf(
fp_cpp,
" if (delay < min_delay)\n delay = min_delay;\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,
" 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,
"void Pipeline_Use::add_usage(const Pipeline_Use &pred) {\n");
fprintf(
fp_cpp,
" const Pipeline_Use_Element *predUse = pred.element(i);\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,
" for (uint j = predUse->_lb; j <= predUse->_ub; j++) {\n");
fprintf(
fp_cpp,
" Pipeline_Use_Element *currUse = element(j);\n");
fprintf(
fp_cpp,
"uint Pipeline::operand_latency(uint opnd, const Pipeline *pred) const {\n");
fprintf(
fp_cpp,
" tty->print(\"# operand_latency(%%d), _read_stage_count = %%d\\n\", opnd, _read_stage_count);\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,
" tty->print(\"# operand_latency: writeStage=%%s readStage=%%s, opnd=%%d\\n\", stageName(writeStage), stageName(readStage), opnd);\n");
fprintf(
fp_cpp,
" if (writeStage == stage_undefined || readStage == stage_undefined)\n");
fprintf(
fp_cpp,
" tty->print(\"# operand_latency: delta=%%d\\n\", delta);\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,
"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,
"Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\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,
"void Pipeline_Use_Cycle_Mask::Or(const Pipeline_Use_Cycle_Mask &in2) {\n ");
/* Get the length of all the resource names */ // 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,
" Pipeline_Use_Element(0, %d, %d, false, Pipeline_Use_Cycle_Mask(",
i1,
i1);
fprintf(
fp_cpp,
"const Pipeline_Use Pipeline_Use::elaborated_use(0, 0, %d, (Pipeline_Use_Element *)&elaborated_elements[0]);\n\n",
// Scan the operands, looking for last output stage and number of inputs // Create the list of stages for the operands that are read // Note that we will build a NameList to reduce the number of copies fprintf(
fp_cpp,
"static const uint pipeline_res_or_masks_%03d[%d] = {",
// Create the pipeline class description fprintf(
fp_cpp,
", %d, %s, %d, %d, %s, %s, %s, %s,\n",
fprintf(
fp_cpp,
"\n (enum machPipelineStages * const) pipeline_reads_%03d,\n ",
fprintf(
fp_cpp,
" (enum machPipelineStages * const) pipeline_res_stages_%03d,\n",
// Generate the Node::latency method if _pipeline defined fprintf(
fp_cpp,
"//------------------Inter-Instruction Latency--------------------------------\n");
fprintf(
fp_cpp,
" tty->print(\"# %%4d->latency(%%d)\\n\", _idx, i);\n");
fprintf(
fp_cpp,
" assert(i < len(), \"index not in range\");\n\n");
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,
" if (i < j)\n return currpipe->functional_unit_latency(%d, predpipe);\n\n",
fprintf(
fp_cpp,
" delta = currpipe->operand_latency(k,predpipe);\n\n");
fprintf(
fp_cpp,
" return currpipe->functional_unit_latency(delta, predpipe);\n");
fprintf(
fp_cpp,
" // assert(false, \"pipeline functionality is not defined\");\n");
// Output the list of nop nodes fprintf(
fp_cpp,
"// Descriptions for emitting different functional unit nops\n");
fprintf(
fp_cpp,
"void Bundle::initialize_nops(MachNode * nop_list[%d], Compile *C) {\n",
nopcnt);
// See if the same string is in the table fprintf(
fp_cpp,
" tty->print(\"%%s\", bundle_flags[_flags]);\n");
fprintf(
fp_cpp,
" tty->print(\"%%s%%d instr%%s\", needs_comma ? \", \" : \"\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n");
fprintf(
fp_cpp,
" tty->print(\"%%sresource%%s:\", needs_comma ? \", \" : \"\", (r & (r-1)) != 0 ? \"s\" : \"\");\n");
// --------------------------------------------------------------------------- //------------------------------Utilities to build Instruction Classes-------- // --------------------------------------------------------------------------- fprintf(
fp,
"const RegMask &%sNode::out_RegMask() const { return (%s); }\n",
// Scan the peepmatch and output a test for each instruction fprintf(
fp,
" // Check instruction sub-tree\n");
// If this is not a placeholder // Define temporaries 'inst#', based on parent and parent's input index if(
parent != -
1 ) {
// root was initialized // Test we have the correct instruction by comparing the rule fprintf(
fp,
" matches = matches && ( inst%d->rule() == %s_rule );",
// Check that user did not try to constrain a placeholder "fatal(): Can not constrain a placeholder instruction");
// Scan the peepmatch and output a test for each instruction fprintf(
fp,
" // Check instruction sub-tree\n");
// If this is not a 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,
" > 0 ) {\n Node *n = block->_nodes.at(");
// Test we have the correct instruction by comparing the rule. fprintf(
fp,
" matches = matches && (inst%d != NULL) && (inst%d->rule() == %s_rule);\n",
// Check that user did not try to constrain a placeholder "fatal(): Can not constrain a placeholder instruction");
// Build mapping for register indices, num_edges to input fprintf(
fp,
" // Build map to register info\n");
// If this is not a placeholder // Define temporaries 'inst#', based on self's inst_position // Generate tests for the constraints fprintf(
fp,
" // Check constraints on sub-tree-leaves\n");
// Build mapping from num_edges to local variables // Build constraint tests // indentation and connecting '&&' // Only have '==' relation implemented assert(
false,
"Unimplemented()" );
// Access info on the instructions whose operands are compared // Access info on the operands being compared // Access info on the instructions whose operands are compared // Access info on the operands being compared }
else {
// Else match register // assert( false, "should be a register" ); // fprintf(fp, "phase->eqv( "); // fprintf(fp, "inst%d->in(%d+%d) /* %s */, inst%d->in(%d+%d) /* %s */", // left_index, left_op_base, left_op_index, left_op, // right_index, right_op_base, right_op_index, right_op ); // Check that they are allocated to the same register // Need parameter for index position if not result operand // Must have index into operands fprintf(
fp,
"(inst%d->_opnds[%d]->reg(ra_,inst%d%s) /* %d.%s */",
// Must have index into operands fprintf(
fp,
"/* %d.%s */ inst%d->_opnds[%d]->reg(ra_,inst%d%s)",
// Compare the '->constant()' values fprintf(
fp,
"(inst%d->_opnds[%d]->constant() /* %d.%s */",
fprintf(
fp,
"/* %d.%s */ inst%d->_opnds[%d]->constant())",
// Compare 'base', 'index', 'scale', and 'disp' fprintf(
fp,
" (inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d) /* %d.%s$$base */",
fprintf(
fp,
"/* %d.%s$$base */ inst%d->_opnds[%d]->base(ra_,inst%d,inst%d_idx%d)) &&\n",
fprintf(
fp,
" (inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d) /* %d.%s$$index */",
fprintf(
fp,
"/* %d.%s$$index */ inst%d->_opnds[%d]->index(ra_,inst%d,inst%d_idx%d)) &&\n",
fprintf(
fp,
" (inst%d->_opnds[%d]->scale() /* %d.%s$$scale */",
fprintf(
fp,
"/* %d.%s$$scale */ inst%d->_opnds[%d]->scale()) &&\n",
fprintf(
fp,
" (inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d) /* %d.%s$$disp */",
fprintf(
fp,
"/* %d.%s$$disp */ inst%d->_opnds[%d]->disp(ra_,inst%d,inst%d_idx%d))\n",
// Compare the condition code being tested assert(
false,
"Unimplemented()" );
assert(
false,
"ShouldNotReachHere()" );
// Advance to next constraint // // 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); // Construct the new sub-tree fprintf(
fp,
" // IF instructions and constraints matched\n");
fprintf(
fp,
" // generate the new sub-tree\n");
fprintf(
fp,
" assert( true, \"Debug stopping point\");\n");
// Get the root of the new sub-tree // Then install the use-operands for the new sub-tree // preplace->reset(); // reset breaks iteration // find the name of the OperandForm from the local name // 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 fprintf(
fp,
" root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",
// If new instruction captures bottom type // Get bottom type from instruction whose result we are replacing // Define result register and result operand fprintf(
fp,
" root->_opnds[0] = inst%d->_opnds[0]->clone(C); // result\n",
inst_num);
fprintf(
fp,
" // ----- Done with initial setup -----\n");
// 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",
fprintf(
fp,
" root->add_req( inst%d->in(x%d) );\n",
fprintf(
fp,
" // no ideal edge for constants after matching\n");
fprintf(
fp,
" root->_opnds[%d] = inst%d->_opnds[%d]->clone(C);\n",
// Replacing subtree with empty-tree assert(
false,
"ShouldNotReachHere();");
// Return the new sub-tree fprintf(
fp,
" return root; // return new root;\n");
// Define the Peephole method for an instruction node // Generate Peephole function header fprintf(
fp,
"MachNode *%sNode::peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ) {\n",
node->
_ident);
// Identify the maximum instruction position, // generate temporaries that hold current instruction // MachNode *inst0 = NULL; // MachNode *instMAX = NULL; 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 // 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 // Scan the peepmatch and output a test for each instruction // Check constraints and build replacement inside scope fprintf(
fp,
" // If instruction subtree matches\n");
// Generate tests for the constraints // Construct the new sub-tree // End of scope for this peephole's constraints // Closing brace '}' to make each peephole rule individually selectable fprintf(
fp,
" return NULL; // No peephole rules matched\n");
// Define the Expand method for an instruction node unsigned cnt = 0;
// Count nodes we have expand into // 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");
// If necessary, generate any operands created in expand rule assert(
frm,
"Invalid entry in new operands list of expand rule");
fprintf(
fp,
" MachOper *op%d = new (C) %sOper();\n",
fprintf(
fp,
" MachOper *op%d = new (C) %sOper(%s);\n",
// Generate the temps to use for DAG building for(i = 0; i <
numo; i++) {
// Build mapping from num_edges to local variables 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. fprintf(
fp,
" idx0--; // Adjust base because memory edge hasn't been inserted yet\n");
fprintf(
fp,
" unsigned idx%d = idx%d + num%d;\n",
// Declare variable to hold root of expansion // Iterate over the instructions 'node' expands into // Build the node for the instruction // Add control edge for this node // Build the operand for the value this node defines. assert(
form,
"'new_id' must be a defined form name");
// Grab the InstructForm for the new instruction fprintf(
fp,
" ((MachFastLockNode*)n%d)->_counters = _counters;\n",
cnt);
fprintf(
fp,
" n%d->set_opnd_array(0, state->MachOperGenerator( %s, C ));\n",
// get the formal operand NameList // Handle any memory operand "expand rule member needs memory but top-level inst doesn't have any" );
fprintf(
fp,
" n%d->add_req(_in[1]);\t// Add memory edge\n",
cnt);
// Iterate over the new instruction's operands // Use 'parameter' at current position in list of new instruction's formals // instead of 'opid' when looking up info internal to new_inst // Check for an operand which is created in the expand rule // If there is no use of the created operand, just skip it //Copy the operand from the original made above fprintf(
fp,
" n%d->set_opnd_array(%d, op%d->clone(C)); // %s\n",
// Check for who defines this operand & add edge if needed // Use operand name to get an index into instruction component list // ins = (InstructForm *) _globalNames[new_id]; // For the add_req calls below to work correctly they need // to added in the same order that a match would add them. // This means that they would need to be in the order of // the components list instead of the formal parameters. // This is a sort of hidden invariant that previously // wasn't checked and could lead to incorrectly syntax_err(
node->
_linenum,
"For expand in %s to work, parameter declaration order in %s must follow matchrule\n",
// Copy the operand from the ExpandNode to the new node fprintf(
fp,
" n%d->set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n",
// For each operand add appropriate input edges by looking at tmp's // Grab corresponding edges from ExpandNode and insert them here // This value is generated by one of the new instructions // Update the DAG tmp's for values defined by this instruction // If this operand is a definition in either an effects rule // Update the temp associated with this operand // Instruction defines a value but user did not declare it // in the 'effect' clause }
// done iterating over a new instruction's operands // Invoke Expand() for the newly created instruction. fprintf(
fp,
" result = n%d->Expand( state, proj_list, mem );\n",
cnt);
}
// done iterating over new instructions }
// done generating expand rule // Generate projections for instruction's additional DEFs and KILLs // Get string representing the MachNode that projections point at // Generate the projections fprintf(
fp,
" // Add projection edges for additional defs or kills\n");
// Examine each component to see if it is a DEF or KILL // Skip the first component, if already handled as (SET dst (...)) // For kills, the choice of projection numbers is arbitrary // Lookup register class associated with operand type assert(
form,
"component type must be a defined form");
// Define the variable "def" to hold new MachProjNodes fprintf(
fp,
" def = new (C) MachTempNode(state->MachOperGenerator( %s, C ));\n",
// The operand for TEMP is already constructed during // this mach node construction, see buildMachNode(). // int idx = node->operand_position_format(comp->_name); // fprintf(fp," set_opnd_array(%d, state->MachOperGenerator( %s, C ));\n", // idx, machOperEnum(op->_ident)); assert(
false,
"can't have temps which aren't registers");
// Define the variable "kill" to hold new MachProjNodes assert(
op,
"Support additional KILLS for base operands");
fprintf(
fp,
"new (C, 1) MachProjNode( %s, %d, (%s), Op_%s );\n",
// Remove duplicated operands and inputs which use the same name. // Seach through match operands for the same name usage. // Build mapping from num_edges to local variables 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");
fprintf(
fp,
" unsigned idx%d = idx%d + num%d;\n",
// Skip first unique operands. // Replace not unique operands with next unique operands. // unique_opnds_idx(i) is unique if unique_opnds_idx(j) is not unique. fprintf(
fp,
" set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n",
// delete not unique edges here fprintf(
fp,
" for(unsigned i = 0; i < num%d; i++) {\n", i);
// delete the rest of edges // If the node is a MachConstantNode, insert the MachConstantBaseNode edge. // NOTE: this edge must be the last input (see MachConstantNode::mach_constant_base_node_input). fprintf(
fp,
" add_req(C->mach_constant_base_node());\n");
//------------------------------Emit Routines---------------------------------- // Special classes and routines for defining node emit routines which output // target specific instruction object encodings. // Define the ___Node::emit() routine // (1) void ___Node::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // (2) // ... encoding defined by user // Temporaries that describe current operand // Stable state, set by constructor // Track necessary state when identifying a replacement variable // A replacement variable or one of its subfields // Obtain replacement variable from list // A replacement variable, '$' prefix // check_rep_var( rep_var ); "'primary', 'secondary' and 'tertiary' don't follow operand.");
"Replacement variable %s not allowed in instruct %s (only in MachConstantNode).\n",
// Lookup its position in parameter list "Replacement variable %s not found in enc_class %s.\n",
// Lookup the corresponding ins_encode parameter "Parameter %s not passed to enc_class %s from instruct %s.\n",
// Check if instruction's actual parameter is a local name in the instruction // Note: assert removed to allow constant and symbolic parameters // assert( opc, "replacement variable was not found in local names"); // Lookup the index position iff the replacement variable is a localName // This is a local in the instruction // Update local state info. // Do not support consecutive operands. // Instruction provided a constant expression // Check later that encoding specifies $$$constant to resolve as constant // Instruction provided an opcode: "primary", "secondary", "tertiary" // Check later that encoding specifies $$$constant to resolve as constant // Instruction provided a literal register name for this parameter // Check that encoding specifies $$$reg to resolve.as register. // Check for unimplemented functionality before hard failure assert(
false,
"ShouldNotReachHere()");
}
// done checking which operand this is. // A subfield variable, '$$' prefix // Check for fields that may require relocation information. // Then check that literal register parameters are accessed with 'reg' or 'constant' assert(
_opclass,
"Must use operand or operand class before '$disp'");
// Only have an operand class, generate run-time check for relocation // Do precise check on operand: is it a ConP or not // Check interface for value of displacement "$disp can only follow memory interface operand");
"$disp can only follow memory interface operand");
// MemInterface::disp contains a replacement variable, // Check if this matches a ConP // Lookup replacement variable, in operand's component list // Lookup operand form for replacement variable's type assert(
op,
"Attempting to emit a non-register or non-constant");
// Check if this is a constant // Check which constant this name maps to: _c0, _c1, ..., _cn // const int idx = _operand.constant_position(_AD.globalNames(), comp); // assert( idx != -1, "Constant component not found in operand"); // No longer true that idealP is always an oop // The only non-constant allowed access to disp is an operand sRegX in a stackSlotX assert(
false,
"fatal(); Only stackSlots can access a non-constant using 'disp'");
}
// finished with precise check of operand for relocation. }
// finished with subfield variable // Check operand for type of constant // No longer true that idealP is always an oop // // _must_reloc = true; // No relocation information needed // User-provided literals may not require relocation information !!!!! // Calls containing labels require relocation // literal register parameter must be accessed as a 'reg' field. assert(
false,
"invalid access to literal register parameter");
// literal constant parameters must be accessed as a 'constant' field assert(
false,
"invalid access to literal constant parameter");
}
// end replacement and/or subfield // Handle subfield and replacement variables. // Check for emit prefix, '$$emit32' // Update state for replacement variables // A replacement variable or one of its subfields // Obtain replacement variable from list // const char *ec_rep_var = encoding->_rep_vars.iter(); // A subfield variable, '$$' prefix // skip trailing $Address // A replacement variable, '$' prefix // handle $rev_var$$base$$Register and $rev_var$$index$$Register by // producing as_Register(opnd_array(#)->base(ra_,this,idx1)). // emit the operand reference }
// end replacement and/or subfield // "emit_d32_reloc(" or "emit_hi_reloc" or "emit_lo_reloc" // Emit the function name when generating an emit function // In general, relocatable isn't known at compiler compile time. // Check results of prior scan // Definitely don't need relocation information // Must emit relocation information // Emit RUNTIME CHECK to see if value needs relocation info // If emitting a relocatable address, use 'emit_d32_reloc' "Must be emitting either a displacement or a constant");
fprintf(
_fp,
"if ( opnd_array(%d)->%s_is_oop() ) {\n",
// Relocation of 16-bit values is not supported // No relocation done for 16-bit values // Relocation of 8-bit values is not supported // No relocation done for 8-bit values // Not an emit# command, just output the replacement string. // Get ready for next state collection. // recognizes names which represent MacroAssembler register types // and return the conversion function to build them from OptoReg if (
strcmp(
rep_var,
"$FloatRegister") == 0)
return "as_FloatRegister";
if (
strcmp(
rep_var,
"$XMMRegister") == 0)
return "as_XMMRegister";
// A subfield variable, '$$subfield' // $reg form or the $Register MacroAssembler type conversions "Must use this subfield after operand");
// Add parameter for index position, if not result operand // Register literal has already been sent to output file, nothing more needed "Must use this subfield after operand");
"Must use this subfield after operand");
// Cosntant literal has already been sent to output file, nothing more needed assert(
false,
"UnImplemented()");
// A replacement variable, originally '$' "Missing $%s opcode definition in %s, used by encoding %s\n",
fprintf(
_fp,
"as_Register(ra_->get_encode(in(mach_constant_base_node_input())))");
fprintf(
_fp,
"InternalAddress(__ code()->consts()->start() + constant_offset())");
// Lookup its position in parameter list "Replacement variable %s not found in enc_class %s.\n",
// Lookup the corresponding ins_encode parameter // Check if instruction's actual parameter is a local name in the instruction // Note: assert removed to allow constant and symbolic parameters // assert( opc, "replacement variable was not found in local names"); // Lookup the index position iff the replacement variable is a localName // This operand isn't a normal input so printing it is done // Output the emit code for this operand "Previous emit $operand does not match current");
// else check if it is a constant expression // Removed following assert to allow primitive C types as arguments to encodings // assert( _constant_status == LITERAL_ACCESSED, "Must be processing a literal constant parameter"); // else check if "primary", "secondary", "tertiary" "Missing $%s opcode definition in %s\n",
// Instruction provided a literal register name for this parameter // Check that encoding specifies $$$reg to resolve.as register. // Check for unimplemented functionality before hard failure assert(
false,
"ShouldNotReachHere()");
};
// end class DefineEmitState // Output instruction's emit prototype fprintf(
fp,
"uint %sNode::size(PhaseRegAlloc *ra_) const {\n",
fprintf(
fp,
" assert(VerifyOops || MachNode::size(ra_) <= %s, \"bad fixed size\");\n",
inst.
_size);
// defineEmit ----------------------------------------------------------------- // Output instruction's emit prototype // If user did not define an encode section, // provide stub that does not generate any machine code. fprintf(
fp,
" // User did not define an encode section.\n");
// Save current instruction's starting address (helps with relocation). // For MachConstantNodes which are ideal jump nodes, fill the jump table. fprintf(
fp,
" ra_->C->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");
// Output each operand's offset into the array of registers. // Output this instruction's encodings // Output user-defined encoding // Process list of user-defined strings, // and occurrences of replacement variables. // Replacement Vars are pushed into a list and then output // Emit this code section // A replacement variable or one of its subfields // Obtain replacement variable from list }
// end while instruction's encodings // Check if user stated which encoding to user fprintf(
fp,
" // User did not define which encode class to use.\n");
// defineEvalConstant --------------------------------------------------------- // Output instruction's emit prototype // For ideal jump nodes, add a jump-table entry. fprintf(
fp,
" _constant = C->constant_table().add_jump_table(this);\n");
// If user did not define an encode section, // provide stub that does not generate any machine code. fprintf(
fp,
" // User did not define an encode section.\n");
// Output this instruction's encodings // Output user-defined encoding // Process list of user-defined strings, // and occurrences of replacement variables. // Replacement Vars are pushed into a list and then output // Emit this code section // A replacement variable or one of its subfields // Obtain replacement variable from list }
// end while instruction's encodings // Check if user stated which encoding to user fprintf(
fp,
" // User did not define which encode class to use.\n");
// --------------------------------------------------------------------------- //--------Utilities to build MachOper and MachNode derived Classes------------ // --------------------------------------------------------------------------- //------------------------------Utilities to build Operand Classes------------ fprintf(
fp,
"const RegMask *%sOper::in_RegMask(int index) const {\n",
// Assert that the index is in range. fprintf(
fp,
" assert(0 <= index && index < %d, \"index out of range\");\n",
// Figure out if all RegMasks are the same. // Return the sole RegMask. fprintf(
fp,
" return &(Compile::current()->FIRST_STACK_mask());\n");
// Build a switch statement to return the desired mask. fprintf(
fp,
" case %d: return &(Compile::current()->FIRST_STACK_mask());\n",
index);
// generate code to create a clone for a class derived from MachOper // (0) MachOper *MachOperXOper::clone(Compile* C) const { // (1) return new (C) MachXOper( _ccode, _c0, _c1, ..., _cn); // Check for constants that need to be copied over // generate parameters for constants assert(
num_consts == 0,
"Currently support zero or one constant per operand clone function");
fprintf(
fp,
"uint %sOper::cmp( const MachOper &oper ) const { return opcode() == oper.opcode(); }\n",
operand);
// Helper functions for bug 4796752, abstracted with minimal modification // from define_oper_interface() // Check for replacement variable // Lookup replacement variable, rep_var, in operand's component list assert(
comp !=
NULL,
"Replacement variable not found in components");
// Lookup operand form for replacement variable's type assert(
op,
"Attempting to emit a non-register or non-constant");
// Check for replacement variable // Lookup replacement variable, rep_var, in operand's component list assert(
comp !=
NULL,
"Replacement variable not found in components");
// Lookup operand form for replacement variable's type assert(
op,
"Attempting to emit a non-register or non-constant");
// Check that this is a constant and find constant's index: // Check that this is a register // Check that this is a constant pointer // Define a MachOper interface methods // Generate access method for base, index, scale, disp, ... fprintf(
fp,
"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");
fprintf(
fp,
"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");
// Check for hexadecimal value OR replacement variable // Lookup replacement variable, rep_var, in operand's component list assert(
comp !=
NULL,
"Replacement variable not found in components");
// Lookup operand form for replacement variable's type assert(
op,
"Attempting to emit a non-register or non-constant");
// Check that this is a register or a constant and generate code: fprintf(
fp,
" return (int)ra_->get_encode(node->in(idx");
// StackSlot for an sReg comes either from input node or from self, when idx==0 fprintf(
fp,
" // Access register number for input operand\n");
fprintf(
fp,
" return ra_->reg2offset(ra_->get_reg_first(node->in(idx)));/* sReg */\n");
fprintf(
fp,
" // Access register number from myself\n");
fprintf(
fp,
" return ra_->reg2offset(ra_->get_reg_first(node));/* sReg */\n");
// Check which constant this name maps to: _c0, _c1, ..., _cn assert(
idx != -
1,
"Constant component not found in operand");
// Output code for this constant, type dependent. assert(
false,
"Attempting to emit a non-register or non-constant");
assert(
false,
"Do not support octal or decimal encode constants");
// Found a memory access using a constant pointer for a displacement // and a base register containing an integer offset. // In this case the base and disp are reversed with respect to what // is expected by MachNode::get_base_and_disp() and MachNode::adr_type(). // Provide a non-NULL return for disp_as_type() that will allow adr_type() // to correctly compute the access type for alias analysis. // See BugId 4796752, operand indOffset32X in i486.ad fprintf(
fp,
" virtual const TypePtr *disp_as_type() const { return _c%d; }\n",
idx);
// Construct the method to copy _idx, inputs and operands to new node. fprintf(
fp_cpp,
"// Copy _idx, inputs and operands to new node\n");
fprintf(
fp_cpp,
"void MachNode::fill_new_machnode( MachNode* node, Compile* C) const {\n");
fprintf(
fp_cpp,
" // This architecture does not have cisc or short branch instructions\n");
// New node must use same node index for access through allocator's tables // Copy machine-independent inputs // Copy machine operands to new MachNode fprintf(
fp_cpp,
" // Copy my operands, except for cisc position\n");
fprintf(
fp_cpp,
" assert( node->num_opnds() == (uint)nopnds, \"Must have same number of operands\");\n");
//------------------------------defineClasses---------------------------------- // Define members of MachNode and MachOper classes based on // operand and instruction lists // Define the contents of an array containing the machine register names // Define an array containing the machine register encoding values // Generate an enumeration of user-defined register classes // and a list of register masks, one for each class. // Only define the RegMask value objects in the expand file. // Declare each as an extern const RegMask ...; in ad_<arch>.hpp // build_register_masks(fp); // Define the pipe_classes // Generate Machine Classes for each operand defined in AD file fprintf(
fp,
"//------------------Define classes derived from MachOper---------------------\n");
// Iterate through all operands // Ensure this is a machine-world instruction // The declaration of labelOper is in machine-independent file: machnode fprintf(
fp,
"uint %sOper::opcode() const { return %s; }\n",
// // Currently all XXXOper::Hash() methods are identical (990820) // define_hash(fp, oper->_ident); // // Currently all XXXOper::Cmp() methods are identical (990820) // define_cmp(fp, oper->_ident); // The declaration of methodOper is in machine-independent file: machnode fprintf(
fp,
"uint %sOper::opcode() const { return %s; }\n",
// // Currently all XXXOper::Hash() methods are identical (990820) // define_hash(fp, oper->_ident); // // Currently all XXXOper::Cmp() methods are identical (990820) // define_cmp(fp, oper->_ident); // // Currently all XXXOper::Hash() methods are identical (990820) // define_hash(fp, oper->_ident); // // Currently all XXXOper::Cmp() methods are identical (990820) // define_cmp(fp, oper->_ident); // side-call to generate output that used to be in the header file: // Generate Machine Classes for each instruction defined in AD file fprintf(
fp,
"//------------------Define members for classes derived from MachNode----------\n");
// Output the definitions for out_RegMask() // & kill_RegMask() // Ensure this is a machine-world instruction // Output the definitions for expand rules & peephole rules // Ensure this is a machine-world instruction // If there are multiple defs/kills, or an explicit expand rule, build rule // If there is an explicit peephole rule, build it // Output code to convert to the cisc version, if applicable // Output code to convert to the short branch version, if applicable // Construct the method called by cisc_version() to copy inputs and operands. // Output the definitions for labels // Ensure this is a machine-world instruction // Access the fields for operand Label fprintf(
fp,
" labelOper* oper = (labelOper*)(opnd_array(%d));\n",
fprintf(
fp,
" oper->_block_num = block_num;\n");
fprintf(
fp,
" labelOper* oper = (labelOper*)(opnd_array(%d));\n",
fprintf(
fp,
" *block_num = oper->_block_num;\n");
// Output the definitions for methods // Ensure this is a machine-world instruction // Access the fields for operand Label // Access the method's address fprintf(
fp,
" ((methodOper*)opnd_array(%d))->_method = method;\n",
// Define this instruction's number of relocation entries, base is '0' // Output the definition for number of relocation entries // Output the definitions for code generation // address ___Node::emit(address ptr, PhaseRegAlloc *ra_) const { // // ... encoding defined by user // Ensure this is a machine-world instruction // side-call to generate output that used to be in the header file: // Output the definitions for alias analysis // Ensure this is a machine-world instruction // Analyze machine instructions that either USE or DEF memory. // Some guys kill all of memory fprintf(
fp,
"const MachOper* %sNode::memory_operand() const { return (MachOper*)-1; }\n",
instr->
_ident);
// Get the length of the longest identifier // Emit specifically for Node(s) // Output the definitions for machine node specific pipeline data // Output the definitions for instruction pipeline static data references // -------------------------------- maps ------------------------------------ // Information needed to generate the ReduceOp mapping for the DFA // Most operands without match rules, e.g. eFlagsReg, do not have a result operand // operand stackSlot does not have a match rule, but produces a stackSlot // Information needed to generate the LeftOp mapping for the DFA // Information needed to generate the RightOp mapping for the DFA // Information needed to generate the Rule names for the DFA // Information needed to generate the swallowed mapping for the DFA // Information needed to generate the decision array for instruction chain rule //---------------------------build_map------------------------------------ // Build mapping from enumeration for densely packed operands // TO result and child types. // Construct this mapping // Output the mapping for operands // Ensure this is a machine-world instruction // Generate the entry for this opcode // Place all user-defined operand classes into the mapping // Place all internally defined operands into the mapping // Place all user-defined instructions into the mapping // Output all simple instruction chain rules first // Ensure this is a machine-world instruction // Ensure this is a machine-world instruction // Output all instructions that are NOT simple chain rules // Ensure this is a machine-world instruction // Ensure this is a machine-world instruction // Helper function for buildReduceMaps //---------------------------generate_assertion_checks------------------- //---------------------------addSourceBlocks----------------------------- //---------------------------addHeaderBlocks----------------------------- //-------------------------addPreHeaderBlocks---------------------------- // Output #defines from definition block //---------------------------buildReduceMaps----------------------------- // Build mapping from enumeration for densely packed operands // TO result and child types. // The emit bodies currently require functions defined in the source block. // Build external declarations for mappings // Construct Save-Policy array fprintf(
fp_cpp,
"// Map from machine-independent register number to register_save_policy\n");
const char *
comma = (
next !=
NULL) ?
"," :
" // no trailing comma";
// Construct Native Save-Policy array fprintf(
fp_cpp,
"// Map from machine-independent register number to c_reg_save_policy\n");
const char *
comma = (
next !=
NULL) ?
"," :
" // no trailing comma";
// Construct Register Save Type array fprintf(
fp_cpp,
"// Map from machine-independent register number to register_save_type\n");
const char *
comma = (
next !=
NULL) ?
"," :
" // no trailing comma";
// Construct the table for reduceOp // Construct the table for leftOp // Construct the table for rightOp // Construct the table of rule names // Construct the boolean table for subsumed operands // // // Preserve in case we decide to use this table instead of another //// Construct the boolean table for instruction chain rules //OutputInstChainRule output_inst_chain(fp_hpp, fp_cpp, _globalNames, *this); //build_map(output_inst_chain); //---------------------------buildMachOperGenerator--------------------------- // Recurse through match tree, building path through corresponding state tree, // Until we reach the constant we are looking for. // Base Case: access constant in ideal node linked to current state node // Each type of constant has its own access function fprintf(
fp,
"_leaf->bottom_type()->is_ptr()");
fprintf(
fp,
"_leaf->bottom_type()->is_narrowoop()");
// !!!!! - Update if adding a machine-independent constant type assert(
false,
"Unsupported constant type, pointer or indefinite");
fprintf(
fp,
"_leaf->as_Bool()->_test._test");
assert(
false,
"Unsupported constant type");
// If constant is in left child, build path and recurse // If constant is in right child, build path and recurse assert(
false,
"ShouldNotReachHere()");
// Generate code that is executed when generating a specific Machine Operand // Generate the case statement for this opcode // Access parameters for constructor from the stat object // Build access to condition code value // Build switch to invoke "new" MachNode or MachOper // Build switch to invoke 'new' for a specific MachOper "//------------------------- MachOper Generator ---------------\n");
"// A switch statement on the dense-packed user-defined type system\n" "// that invokes 'new' on the corresponding class constructor.\n");
// Place all user-defined operands into the mapping // Ensure this is a machine-world instruction // Do not iterate over operand classes for the operand generator!!! // Place all internal operands into the mapping // Generate the case statement for this opcode // Generate the default case for switch(opcode) fprintf(
fp_cpp,
" fprintf(stderr, \"Default MachOper Generator invoked for: \\n\");\n");
fprintf(
fp_cpp,
" fprintf(stderr, \" opcode = %cd\\n\", opcode);\n",
'%');
// Generate the closing for method Matcher::MachOperGenerator //---------------------------buildMachNode------------------------------------- // Build a new MachNode, for MachNodeGenerator or cisc-spilling // Create the MachNode object // Instruction that contains operands which are not in match rule. // Check if the first post-match component may be an interesting def // Insert operands that are not in match-rule. // Only insert a DEF if the do_care flag is set // Check if we don't care about DEFs or KILLs that are not USEs // For each operand not in the match rule, call MachOperGenerator // with the enum for the opcode that needs to be built. // An instruction that chains from a constant! // In this case, we need to subsume the constant into the node // at operand position, oper_input_base(). // Check for multiple constants and then fill them in. // Just like MachOperGenerator // Look up the number of constants // Fill in the bottom_type where requested //---------------------------declare_cisc_version------------------------------ // Build CISC version of this instruction fprintf(
fp_hpp,
" virtual MachNode *cisc_version(int offset, Compile* C);\n");
fprintf(
fp_hpp,
" virtual const RegMask *cisc_RegMask() const { return _cisc_RegMask; }\n");
//---------------------------define_cisc_version------------------------------- // Build CISC version of this instruction // Set the correct reg_mask_or_stack for the cisc operand // Lookup the correct reg_mask_or_stack // Construct CISC version of this instruction // Create the MachNode object // Fill in the bottom_type where requested fprintf(
fp_cpp,
" // Copy _idx, inputs and operands to new node\n");
// Construct operand to access [stack_pointer + offset] fprintf(
fp_cpp,
" // Construct operand to access [stack_pointer + offset]\n");
// Return result and exit scope //---------------------------declare_short_branch_methods---------------------- // Build prototypes for short branch methods fprintf(
fp_hpp,
" virtual MachNode *short_branch_version(Compile* C);\n");
//---------------------------define_short_branch_methods----------------------- // Build definitions for short branch methods // Construct short_branch_version() method. fprintf(
fp_cpp,
"// Build short branch version of this instruction\n");
// Create the MachNode object // Fill in the bottom_type where requested // Short branch version must use same node index for access // through allocator's tables fprintf(
fp_cpp,
" // Copy _idx, inputs and operands to new node\n");
// Return result and exit scope //---------------------------buildMachNodeGenerator---------------------------- // Build switch to invoke appropriate "new" MachNode for an opcode // Build switch to invoke 'new' for a specific MachNode "//------------------------- MachNode Generator ---------------\n");
"// A switch statement on the dense-packed user-defined type system\n" "// that invokes 'new' on the corresponding class constructor.\n");
// Provide constructor for all user-defined instructions // Ensure that matrule is defined. // Generate the case statement for this instruction // Generate code to construct the new MachNode // Return result and exit scope // Generate the default case for switch(opcode) fprintf(
fp_cpp,
" fprintf(stderr, \"Default MachNode Generator invoked for: \\n\");\n");
fprintf(
fp_cpp,
" fprintf(stderr, \" opcode = %cd\\n\", opcode);\n",
'%');
// Generate the closing for method Matcher::MachNodeGenerator //---------------------------buildInstructMatchCheck-------------------------- // Output the method to Matcher which checks whether or not a specific // instruction has a matching rule for the host architecture. fprintf(
fp_cpp,
"const bool Matcher::has_match_rule(int opcode) {\n");
fprintf(
fp_cpp,
" assert(_last_machine_leaf < opcode && opcode < _last_opcode, \"opcode in range\");\n");
fprintf(
fp_cpp,
"const bool Matcher::_hasMatchRule[_last_opcode] = {\n");
//---------------------------buildFrameMethods--------------------------------- // Output the methods to Matcher which specify frame behavior fprintf(
fp_cpp,
"bool Matcher::stack_direction() const { return %s; }\n\n",
fprintf(
fp_cpp,
"int Compile::sync_stack_slots() const { return %s; }\n\n",
fprintf(
fp_cpp,
"uint Matcher::stack_alignment_in_bytes() { return %s; }\n\n",
// Java Return Address Location // Java Stack Slot Preservation // Top Of Stack Slot Preservation, for both Java and C fprintf(
fp_cpp,
"{ return SharedRuntime::out_preserve_stack_slots(); }\n\n");
// varargs C out slots killed fprintf(
fp_cpp,
"uint Compile::varargs_C_out_slots_killed() const ");
// Java Argument Position fprintf(
fp_cpp,
"void Matcher::calling_convention(BasicType *sig_bt, VMRegPair *regs, uint length, bool is_outgoing) {\n");
// Native Argument Position fprintf(
fp_cpp,
"void Matcher::c_calling_convention(BasicType *sig_bt, VMRegPair *regs, uint length) {\n");
// Java Return Value Location fprintf(
fp_cpp,
"OptoRegPair Matcher::return_value(int ideal_reg, bool is_outgoing) {\n");
// Native Return Value Location fprintf(
fp_cpp,
"OptoRegPair Matcher::c_return_value(int ideal_reg, bool is_outgoing) {\n");
// Inline Cache Register, mask definition, and encoding // Interpreter's Method Oop Register, mask definition, and encoding fprintf(
fp_cpp,
"OptoReg::Name Matcher::interpreter_method_oop_reg() {");
fprintf(
fp_cpp,
"int Matcher::interpreter_method_oop_reg_encode() {");
fprintf(
fp_cpp,
" return _regEncode[interpreter_method_oop_reg()]; }\n\n");
// Interpreter's Frame Pointer Register, mask definition, and encoding fprintf(
fp_cpp,
"OptoReg::Name Matcher::interpreter_frame_pointer_reg() {");
// Frame Pointer definition /* CNC - I can not contemplate having a different frame pointer between Java and native code; makes my head hurt to think about it. fprintf(fp_cpp,"OptoReg::Name Matcher::frame_pointer() const {"); fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n", // (Native) Frame Pointer definition fprintf(
fp_cpp,
"OptoReg::Name Matcher::c_frame_pointer() const {");
// Number of callee-save + always-save registers for calling convention fprintf(
fp_cpp,
"// Number of callee-save + always-save registers\n");
//---------------------------identify_cisc_spilling---------------------------- // Get info for the CISC_oracle and MachNode::cisc_version() // Find the user-defined operand for cisc-spilling // Verify the user's suggestion // Ensure that match field is defined. // Successfully verified operand // N^2 comparison of instructions looking for a cisc-spilling version // Ensure that match field is defined. // Grab the machine type of the operand // Find result type for match // Ensure that match field is defined. //---------------------------build_cisc_spilling------------------------------- // Get info for the CISC_oracle and MachNode::cisc_version() // Output the table for cisc spilling fprintf(
fp_cpp,
"// The following instructions can cisc-spill\n");
// Ensure this is a machine-world instruction //---------------------------identify_short_branches---------------------------- // Get info for our short branch replacement oracle. // Walk over all instructions, checking to see if they match a short // The instruction must have a match rule. //---------------------------identify_unique_operands--------------------------- // Identify unique operands. // Walk over all instructions. // Ensure this is a machine-world instruction