/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*
*/
// FORMS.CPP - Definitions for ADL Parser Forms Classes
#include "adlc.hpp"
//==============================Instructions===================================
//------------------------------InstructForm-----------------------------------
_is_mach_constant(false),
_has_call(false)
{
_insencode = NULL;
_predicate = NULL;
_num_uniq = 0;
_is_cisc_alternate = false;
_is_short_branch = false;
_alignment = 1;
}
_is_mach_constant(false),
_has_call(false)
{
_is_cisc_alternate = false;
_is_short_branch = false;
_alignment = 1;
// Copy parameters
const char *name;
}
InstructForm::~InstructForm() {
}
return (InstructForm*)this;
}
return _ideal_only;
}
}
_components.reset();
return true;
}
}
return false;
}
if (_matrule) {
// Examine each component to see if it is a TEMP
_components.reset();
// Skip the first component, if already handled as (SET dst (...))
return true;
}
}
}
return false;
}
_components.reset();
}
}
return defs_or_kills;
}
// This instruction has an expand rule?
}
// This instruction has a peephole rule?
return _peephole;
}
// This instruction has a peephole rule?
} else {
}
}
// ideal opcode enumeration
// Chain rules do not really have ideal Opcodes; use their source
// operand ideal Opcode instead.
if( is_simple_chain_rule(globalNames) ) {
}
// Operand chain rules do not really have ideal Opcodes
return "Node";
}
// Recursive check on all operands' match rules in my match rule
if ( ! _matrule) return false;
int index = 0;
}
// Recursive check on all operands' match rules in my match rule
if ( ! _matrule) return false;
int index = 0;
return false;
}
// Recursive check on all operands' match rules in my match rule
if ( ! _matrule) return false;
int index = 0;
return false;
}
}
// Return 'true' if this instruction matches an ideal 'Copy*' node
}
// Return 'true' if this instruction is too complex to rematerialize.
// We can prove it is cheap if it has an empty encoding.
// This helps with platform-specific nops like ThreadLocal and RoundFloat.
if (is_empty_encoding())
return 0;
if (is_tls_instruction())
return 1;
return _matrule->is_expensive();
}
// Has an empty encoding if _size is a constant zero or there
// are no ins_encode tokens.
if (_insencode != NULL) {
_insencode->reset();
return 1;
}
}
return 1;
}
return 0;
}
return 1;
}
return 1;
}
}
return 0;
}
// Return 'true' if this instruction matches an ideal 'If' node
return _matrule->is_ideal_if();
}
// Return 'true' if this instruction matches an ideal 'FastLock' node
return _matrule->is_ideal_fastlock();
}
// Return 'true' if this instruction matches an ideal 'MemBarXXX' node
return _matrule->is_ideal_membar();
}
// Return 'true' if this instruction matches an ideal 'LoadPC' node
return _matrule->is_ideal_loadPC();
}
// Return 'true' if this instruction matches an ideal 'Box' node
return _matrule->is_ideal_box();
}
// Return 'true' if this instruction matches an ideal 'Goto' node
return _matrule->is_ideal_goto();
}
// Return 'true' if this instruction matches an ideal 'Jump' node
return _matrule->is_ideal_jump();
}
// Return 'true' if instruction matches ideal 'If' | 'Goto' | 'CountedLoopEnd'
}
// Return 'true' if this instruction matches an ideal 'Return' node
// Check MatchRule to see if the first entry is the ideal "Return" node
int index = 0;
return false;
}
// Return 'true' if this instruction matches an ideal 'Halt' node
int index = 0;
}
// Return 'true' if this instruction matches an ideal 'SafePoint' node
int index = 0;
}
// Return 'true' if this instruction matches an ideal 'Nop' node
}
if ( ! _matrule) return false;
}
// Return 'true' if this instruction matches an ideal 'Call' node
// Check MatchRule to see if the first entry is the ideal "Call" node
int idx = 0;
idx = 0;
idx = 0;
idx = 0;
idx = 0;
idx = 0;
idx = 0;
idx = 0;
return Form::invalid_type;
}
// Return 'true' if this instruction matches an ideal 'Load?' node
return _matrule->is_ideal_load();
}
// Return 'true' if this instruction matches an ideal 'LoadKlass' node
return _matrule->skip_antidep_check();
}
// Return 'true' if this instruction matches an ideal 'Load?' node
return _matrule->is_ideal_store();
}
// Return 'true' if this instruction matches an ideal vector node
}
// Return the input register that must match the output register
// If this is not required, return 0
if(_components.count() == 0) return 0;
_components.reset();
// Check if there is a DEF
// Check that this is a register
if( op ) {
// Remember the local name for equality test later
// Check if a component has the same name and is a USE
do {
return operand_position_format(def_name);
}
}
}
}
return 0;
}
// when chaining a constant to an instruction, returns 'true' and sets opType
}
const char * &opTypeParam) {
}
const char * &opTypeParam, const char * &resultParam) {
// !!!!!
// The source of the chain rule is 'position = 1'
// Here base_operand is looking for an ideal type to be returned (opType).
// if it isn't an ideal constant type, just return
// Ideal constant types also adjust the opType parameter.
return data_type;
}
return data_type;
}
// Check if a simple chain rule
return true;
}
return false;
}
// check for structural rematerialization
bool rematerialize = false;
rematerialize = true;
// Ugly: until a better fix is implemented, disable rematerialization for
// negD nodes because they are proved to be problematic.
if (is_ideal_negD()) {
return false;
}
// Constants
rematerialize = true;
// Pseudo-constants (values easily available to the runtime)
if (is_empty_encoding() && is_tls_instruction())
rematerialize = true;
// 1-input, 1-output, such as copies or increments.
rematerialize = true;
// Check for an ideal 'Load?' and eliminate rematerialize option
rematerialize = false;
}
// Always rematerialize the flags. They are more expensive to save &
// restore than to recompute (and possibly spill the compare's inputs).
Component *c = _components[0];
if( opform ) {
// Avoid the special stack_slots register classes
if( rc_name ) {
// Check for ideal_type of RegFlags
rematerialize = true;
} else
rematerialize = false; // Do not rematerialize things target stk
}
}
}
return rematerialize;
}
// loads from memory, so must check for anti-dependence
if ( skip_antidep_check() ) return false;
// Machine independent loads must be checked for anti-dependences
// !!!!! !!!!! !!!!!
// TEMPORARY
// if( is_simple_chain_rule(globals) ) return false;
// but writes none
return true;
// Check if instruction has a USE of a memory operand class, but no defs
bool USE_of_memory = false;
bool DEF_of_memory = false;
components.reset();
if( !form ) continue;
if( !op ) continue;
// Stack slots are unaliased memory handled by allocator
} else {
DEF_of_memory = true;
}
}
}
}
return (USE_of_memory && !DEF_of_memory);
}
return false;
}
// Machine independent loads must be checked for anti-dependences
// Check if instruction has a USE of a memory operand class, or a def.
int USE_of_memory = 0;
int DEF_of_memory = 0;
components.reset();
if( !form ) continue;
if( !op ) continue;
if( last_memory_DEF != NULL ) {
assert(0 == strcmp(last_memory_DEF, comp->_name), "every memory DEF is followed by a USE of the same name");
}
if (DEF_of_memory == 0) // defs take precedence
} else {
}
}
}
if( (USE_of_memory + DEF_of_memory) > 0 ) {
if( is_simple_chain_rule(globals) ) {
//fprintf(stderr, "Warning: chain rule is not really a memory user.\n");
//((InstructForm*)this)->dump();
// Preceding code prints nothing on sparc and these insns on intel:
// leaP8 leaP32 leaPIdxOff leaPIdxScale leaPIdxScaleOff leaP8 leaP32
// leaPIdxOff leaPIdxScale leaPIdxScaleOff
return NO_MEMORY_OPERAND;
}
if( DEF_of_memory == 1 ) {
if( USE_of_memory == 0 ) {
// unique def, no uses
} else {
// // unique def, some uses
// // must return bottom unless all uses match def
// unique = NULL;
}
} else if( DEF_of_memory > 0 ) {
// multiple defs, don't care about uses
} else if( USE_of_memory == 1) {
// unique use, no defs
} else if( USE_of_memory > 0 ) {
// multiple uses, no defs
} else {
assert(false, "bad case analysis");
}
// process the unique DEF or USE, if there is one
return MANY_MEMORY_OPERANDS;
} else {
}
return pos;
}
}
// missed the memory op??
if( true ) { // %%% should not be necessary
((InstructForm*)this)->dump();
// pretend it has multiple defs and uses
return MANY_MEMORY_OPERANDS;
}
((InstructForm*)this)->dump();
// pretend it has multiple uses and no defs
return MANY_MEMORY_OPERANDS;
}
}
return NO_MEMORY_OPERAND;
}
// This instruction captures the machine-independent bottom_type
// Expected use is for pointer vs oop determination for LoadP
if (needs_base_oop_edge(globals)) return true;
if (is_vector()) return true;
if (is_mach_constant()) return true;
return false;
}
// Access instr_cost attribute or return NULL.
}
}
return NULL;
}
// Return count of top-level operands.
// Need special handling for matching some ideal nodes
// i.e. Matching a return node
/*
if( _matrule ) {
if( strcmp(_matrule->_opType,"Return" )==0 ||
strcmp(_matrule->_opType,"Halt" )==0 )
return 3;
}
*/
return num_opnds;
}
}
uint i;
for (i = 1; i < num_opnds(); ++i) {
if (unique_opnds_idx(i) == idx) {
break;
}
}
}
// Return count of unmatched operands.
return num_post_match_opnds;
}
// Return the number of leaves below this complex operand
if ( ! _matrule) return 0;
// This is a recursive invocation on all operands in the matchrule
}
// Constants in match rule with specified type
if ( ! _matrule) return 0;
// This is a recursive invocation on all operands in the matchrule
}
// Return the register class associated with 'leaf'.
assert( false, "InstructForm::out_reg_class(FormDict &globals); Not Implemented");
return NULL;
}
// Lookup the starting position of inputs we are interested in wrt. ideal nodes
// Need special handling for matching some ideal nodes
// i.e. Matching a return node
// take 1 control and 1 memory edges.
return 2;
}
// The AD file writer is shielded from knowledge of these edges.
// Also skip the base-oop value for uses of derived oops.
// The AD file writer is shielded from knowledge of these edges.
return base;
}
// This function determines the order of the MachOper in _opnds[]
// by writing the operand names into the _components list.
//
// Implementation does not modify state of internal structures
// Add top-level operands to the components
// Add parameters that "do not appear in match rule".
bool has_temp = false;
const char *name;
{
}
if (e != NULL) {
// KILLs must be declared after any TEMPs because TEMPs are real
// uses so their operand numbering must directly follow the real
// inputs from the match rule. Fixing the numbering seems
// complex so simply enforce the restriction during parse.
}
}
if (e) {
}
}
} else {
// This would be a nice warning but it triggers in a few places in a benign way
// if (_matrule != NULL && !expands()) {
// globalAD->syntax_err(_linenum, "%s: %s %s not mentioned in effect or match rule\n",
// _ident, opForm->_ident, name);
// }
}
}
else if (e) {
// Component was found in the list
// Check if there is a new effect that requires an extra component.
// This happens when adding 'USE' to a component that is not yet one.
}
}
} else {
}
// Component positions are zero based.
"Component::DEF can only occur in the first position");
}
}
// Resolving the interactions between expand rules and TEMPs would
// be complex so simply disallow it.
}
return;
}
// Return zero-based position in component list; -1 if not in list.
}
}
// Return zero-based position in component list; -1 if not in list.
}
}
// Return number of relocation entries needed for this instruction.
// Check for "Call" nodes
if ( is_ideal_call() ) ++reloc_entries;
if ( is_ideal_return() ) ++reloc_entries;
if ( is_ideal_safepoint() ) ++reloc_entries;
// Check if operands MAYBE oop pointers, by checking for ConP elements
// Proceed through the leaves of the match-tree and check for ConPs
#ifdef SPARC
#else
#endif
}
++position;
}
}
// Above is only a conservative estimate
// because it did not check contents of operand classes.
// !!!!! !!!!!
// Add 1 to reloc info for each operand class in the component list.
_components.reset();
} else if ( oper ) {
// floats and doubles loaded out of method's constant pool require reloc info
}
}
}
// Float and Double constants may come from the CodeBuffer table
// and require relocatable addresses for access
// !!!!!
// Check for any component being an immediate float or double.
#ifdef SPARC
// sparc required more relocation entries for floating constants
// (expires 9/98)
reloc_entries += 6;
#else
#endif
}
return reloc_entries;
}
// Utility function defined in archDesc.cpp
// Return the result of reducing an instruction
_components.reset();
// Override this if the rule is a store operation:
result = "Universe";
}
return result;
}
// Return the name of the operand on the right hand side of the binary match
// Return NULL if there is no right hand side
}
// Similar for left
}
// Base class for this instruction, MachNode except for calls
return "MachCallStaticJavaNode";
}
return "MachCallDynamicJavaNode";
}
return "MachCallRuntimeNode";
}
return "MachCallLeafNode";
}
else if (is_ideal_return()) {
return "MachReturnNode";
}
else if (is_ideal_halt()) {
return "MachHaltNode";
}
else if (is_ideal_safepoint()) {
return "MachSafePointNode";
}
else if (is_ideal_if()) {
return "MachIfNode";
}
else if (is_ideal_goto()) {
return "MachGotoNode";
}
else if (is_ideal_fastlock()) {
return "MachFastLockNode";
}
else if (is_ideal_nop()) {
return "MachNopNode";
}
else if (is_mach_constant()) {
return "MachConstantNode";
}
else if (captures_bottom_type(globals)) {
return "MachTypeNode";
} else {
return "MachNode";
}
assert( false, "ShouldNotReachHere()");
return NULL;
}
// Compare the instruction predicates for textual equality
// no predicates means they are identical
return true;
}
// compare the predicates
return true;
}
}
return false;
}
// Check if this instruction can cisc-spill to 'alternate'
// Do not replace if a cisc-version has been found.
if( cisc_spill_operand() != Not_cisc_spillable ) return false;
cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type);
if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != NULL) && equivalent_predicates(this, instr) ) {
// Do not support cisc-spilling for destination operands and
// make sure they have the same number of operands.
instr->set_cisc_alternate(true);
if( AD._cisc_spill_debug ) {
}
// Record that a stack-version of the reg_mask is needed
// !!!!!
} else {
}
} else {
}
return (cisc_spill_operand != Not_cisc_spillable);
}
// Check to see if this instruction can be replaced with the short branch
// instruction `short-branch'
this != short_branch && // Don't match myself
!is_short_branch() && // Don't match another short branch variant
reduce_result() != NULL &&
// The instructions are equivalent.
// Now verify that both instructions have the same parameters and
// the same effects. Both branch forms should have the same inputs
// and resulting projections to correctly replace a long branch node
// with corresponding short branch node during code generation.
bool different = false;
different = true;
} else if (_components.count() > 0) {
_components.reset();
if (short_comp == NULL ||
different = true;
break;
}
}
different = true;
}
if (different) {
globalAD->syntax_err(short_branch->_linenum, "Instruction %s and its short form %s have different parameters\n", _ident, short_branch->_ident);
}
}
return true;
}
return false;
}
// --------------------------- FILE *output_routines
//
// Generate the format call for the replacement variable
// Handle special constant table variables.
return;
}
return;
}
return;
}
// Find replacement variable's type
return;
}
// Lookup the index position of the replacement variable
if ( idx == -1 ) {
globalAD->syntax_err(_linenum, "Could not find replacement variable %s in format statement of %s.\n",
return;
}
if (is_noninput_operand(idx)) {
// This component isn't in the input array. Print out the static
// name of the register.
} else {
}
} else {
// Output the format call for this operand
if (idx == 0)
else
}
}
// Seach through operands to determine parameters unique positions.
int i;
_uniq_idx_length = 0;
if ( nopnds > 0 ) {
// Allocate index array. Worst case we're mapping from each
// component back to an index and any DEF always goes at 0 so the
// length of the array has to be the number of components + 1.
for( i = 0; i < _uniq_idx_length; i++ ) {
uniq_idx[i] = i;
}
}
// Do it only if there is a match rule and no expand rule. With an
// expand rule it is done by creating new mach node in Expand()
// method.
const char *name;
bool has_dupl_use = false;
_parameters.reset();
count = 0;
int position = 0;
int uniq_position = 0;
_components.reset();
if( sets_result() ) {
position++;
}
// The next code is copied from the method operand_position().
// When the first component is not a DEF,
// leave space for the result operand!
++position;
}
if( ++count > 1 ) {
has_dupl_use = true;
} else {
}
}
++position;
if( position != 1 )
--position; // only use two slots for the 1st USE_DEF
}
}
}
if( has_dupl_use ) {
for( i = 1; i < nopnds; i++ )
if( i != uniq_idx[i] )
break;
int j = i;
for( ; i < nopnds; i++ )
if( i == uniq_idx[i] )
uniq_idx[i] = j++;
num_uniq = j;
}
}
}
// Generate index values needed for determining the operand position
void InstructForm::index_temps(FILE *fp, FormDict &globals, const char *prefix, const char *receiver) {
// Compute the index into vector of operand pointers:
// idx0=0 is used to indicate that info comes from this same node, not from input edge.
// idx1 starts at oper_input_base()
if ( cur_num_opnds >= 1 ) {
// Generate starting points for other unique operands if they exist
if( *receiver == 0 ) {
} else {
}
}
}
if( *receiver != 0 ) {
// This value is used by generate_peepreplace when copying a node.
// Don't emit it in other cases since it can hide bugs with the
// use invalid idx's.
}
}
// ---------------------------
// !!!!! !!!!!
// Check that a "label" operand occurs last in the operand list, if present
return true;
}
}
}
}
}
}
//------------------------------build_predicate--------------------------------
// Build instruction predicates. If the user uses the same operand name
// twice, we need to check that the operands are pointer-eequivalent in
// the DFA during the labeling process.
// Start with the predicate supplied in the .ad file.
if( _predicate ) {
s += strlen(s);
}
// Handle many pairs
else { // All tests must pass, so use '&&'
strcpy(s," && ");
s += strlen(s);
}
// Add predicate to working buffer
s += strlen(s);
s += strlen(s);
s += strlen(s);
}
}
else {
}
return new Predicate(s);
}
//------------------------------EncodeForm-------------------------------------
// Constructor
}
EncodeForm::~EncodeForm() {
}
// record a new register class
return encClass;
}
// Lookup the function body for an encoding class
return encClass;
}
// Lookup the function body for an encoding class
return code;
}
// Lookup the function body for an encoding class
return className;
}
}
const char *name;
}
}
//------------------------------EncClass---------------------------------------
}
}
// Add a parameter <type,name> pair
}
// Verify operand types in parameter list
// !!!!!
return false;
}
// Add the decomposed "code" sections of an encoding's code-block
}
// Add the decomposed "replacement variables" of an encoding's code-block
}
// Lookup the function body for an encoding class
++position;
}
return -1;
}
// Check after parsing
// 1!!!!
// Check that each replacement variable, '$name' in architecture description
// is actually a local variable for this encode class, or a reserved name
// "primary, secondary, tertiary"
return true;
}
}
// Write info to output files
// Output the parameter list
}
// Output the code block
const char *code;
// A replacement variable
} else {
// A section of code
}
}
}
//------------------------------Opcode-----------------------------------------
}
}
}
}
}
return Opcode::NOT_AN_OPCODE;
}
// Default values previously provided by MachNode::primary()...
// Check if user provided any opcode definitions
if( this != NULL ) {
// Update 'value' if user provided a definition in the instruction
switch (desired_opcode) {
case PRIMARY:
description = "primary()";
break;
case SECONDARY:
description = "secondary()";
break;
case TERTIARY:
description = "tertiary()";
break;
default:
assert( false, "ShouldNotReachHere();");
break;
}
}
}
}
}
// Write info to output files
}
//------------------------------InsEncode--------------------------------------
}
}
// Add "encode class name" and its parameters
// add_parameter(NameList::_signal);
return encode;
}
// Access the list of encodings
// _parameter.reset();
}
}
// Obtain parameter name from zero based index
// Remove '$' if parser placed it there.
}
}
// Write info to output files
// Output the encoding being used
// Output its parameter list, if any
bool first_param = true;
// Output the ',' between parameters
first_param = false;
// Output the parameter
} // done with parameters
} // done with encodings
}
//------------------------------Effect-----------------------------------------
assert( false,"Invalid effect name specified\n");
}
switch (_usedef) {
default: assert(false, "unknown effect");
}
}
}
}
// Dynamic type check
return (Effect*)this;
}
// True if this component is equal to the parameter.
return (_use_def == use_def_kill_enum ? true : false);
}
}
}
}
//------------------------------ExpandRule-------------------------------------
}
}
}
}
}
}
// Iterate over the instructions 'node' expands into
// iterate over the operand list
}
}
}
//------------------------------RewriteRule------------------------------------
}
}
}
//==============================MachNodes======================================
//------------------------------MachNodeForm-----------------------------------
}
MachNodeForm::~MachNodeForm() {
}
return (MachNodeForm*)this;
}
//==============================Operand Classes================================
//------------------------------OpClassForm------------------------------------
}
OpClassForm::~OpClassForm() {
}
return (OpClassForm*)this;
}
// Check that my operands have the same interface type
bool first = true;
const char *op_name;
if( first ) {
first = false;
} else {
}
}
return interface;
}
const char *op_name;
}
return true;
}
}
const char *name;
}
}
//==============================Operands=======================================
//------------------------------OperandForm------------------------------------
_interface = NULL;
_predicate = NULL;
_construct = NULL;
}
_interface = NULL;
_predicate = NULL;
_construct = NULL;
}
OperandForm::~OperandForm() {
}
return (OperandForm*)this;
}
return _ideal_only;
}
}
if( _constraint == NULL ) return false;
return _constraint->stack_slots_only();
}
// Access op_cost attribute or return NULL.
}
}
return NULL;
}
// Return the number of leaves below this complex operand
if ( ! _matrule) return 0;
return num_leaves;
}
// Return the number of constants contained within this complex operand
if ( ! _matrule) return 0;
// This is a recursive invocation on all operands in the matchrule
}
// Return the number of constants in match rule with specified type
if ( ! _matrule) return 0;
// This is a recursive invocation on all operands in the matchrule
}
// Return the number of pointer constants contained within this complex operand
if ( ! _matrule) return 0;
// This is a recursive invocation on all operands in the matchrule
}
// If we are matching a constant directly, there are no leaves.
// !!!!!
// Special case operands that do not have a corresponding ideal node.
if( constrained_reg_class() != NULL ) {
edges = 1;
} else {
if( _matrule
if( oper ) {
}
}
}
}
return edges;
}
// Check if this operand is usable for cisc-spilling
return is_cisc_reg;
}
return (my_interface == memory_interface);
}
// node matches ideal 'Bool'
return _matrule->is_ideal_bool();
}
// Require user's name for an sRegX to be stackSlotX
}
return data_type;
}
// Return ideal type, if there is a single ideal type for this operand
// Check for condition code register
// !!!!!
// !!!!! !!!!!
// Check constraints on result's register class
if( registers ) {
// Check for ideal type of entries in register class, all are the same type
// Return substring that names the register's ideal type
}
}
// This operand matches a single type, at the top level.
// Check for ideal type
return "Bool";
// transitive lookup
}
return type;
}
// If there is a single ideal type for this interface field, return it.
const char *field) const {
// Check if "field" is valid for this operand's interface
// !!!!! !!!!! !!!!!
// If a valid field has a constant value, identify "ConI" or "ConP" or ...
// Else, lookup type of field's replacement variable
return ideal_type;
}
}
int size = 0;
if (size == 0) return false;
}
// Check if this is a valid field for this operand,
// Return 'true' if valid, and set the value to the string the user provided.
const char * &value) const {
return false;
}
// Return register class name if a constraint specifies the register class.
if ( _constraint ) {
// !!!!!
}
}
return reg_class;
}
// Return the register class associated with 'leaf'.
return reg_class;
}
// iterate through all base operands
// until we reach the register that corresponds to "leaf"
// This function is not looking for an ideal type. It needs the first
// level user type associated with the leaf.
if( oper ) {
if( reg_class ) {
} else {
// ShouldNotReachHere();
}
} else {
// ShouldNotReachHere();
}
// Increment our target leaf position if current leaf is not a candidate.
// Exit the loop with the value of reg_class when at the correct index
// May iterate through all base operands if reg_class for 'leaf' is NULL
}
return reg_class;
}
// Recursive call to construct list of top-level operands.
// Implementation does not modify state of internal structures
// Add parameters that "do not appear in match rule".
const char *name;
}
}
return;
}
}
// Return zero-based position in component list, only counting constants;
// Return -1 if not in list.
// Iterate through components and count constants preceding 'constant'
int position = 0;
_components.reset();
// Special case for operands that take a single user-defined operand
// Skip the initial definition in the component list.
// Lookup operand form for replacement variable's type
if( oper ) {
++position;
}
}
}
// Check for being passed a component that was not in the list
return position;
}
// Provide position of constant by "name"
return idx;
}
// Return zero-based position in component list, only counting constants;
// Return -1 if not in list.
// Iterate through components and count registers preceding 'last'
_components.reset();
// Special case for operands that take a single user-defined operand
// Skip the initial definition in the component list.
// Lookup operand form for component's type
if( oper ) {
++position;
}
}
}
return position;
}
return _ident;
}
// Return the name of the operand on the right hand side of the binary match
// Return NULL if there is no right hand side
}
// Similar for left
}
// --------------------------- FILE *output_routines
//
// Output code for disp_is_oop, if true.
// Check it is a memory interface with a non-user-constant disp field
if ( this->_interface == NULL ) return;
if ( mem_interface == NULL ) return;
if ( *disp != '$' ) return;
// Lookup replacement variable in operand's component list
// Lookup operand form for replacement variable's type
// Check if this is a ConP, which may require relocation
// Find the constant's index: _c0, _c1, _c2, ... , _cN
}
}
// Generate code for internal and external format methods
//
// internal access to reg# node->_idx
// access to subsumed constant _c0, _c1,
// !!!!! !!!!!
// Special format for Stack Slot Register
} else {
dump();
assert( false,"Internal error:\n output_internal_operand() attempting to output other than a Register or Constant");
}
}
// Similar to "int_format" but for cases where data is external to operand
// external access to reg# node->in(idx)->_idx,
// Special format for Stack Slot Register
} else {
assert( false,"Internal error:\n output_external_operand() attempting to output other than a Register or Constant");
}
}
switch(const_type) {
default:
assert( false, "ShouldNotReachHere()");
}
}
// Return the operand form corresponding to the given index, else NULL.
// !!!!!
// Check behavior on complex operands
if( n_consts > 0 ) {
uint i = 0;
const char *type;
_components.reset();
// Current operand is THE operand
if ( index == 0 ) {
return this;
}
} // end if NULL
else {
// Skip the first component, it can not be a DEF of a constant
do {
// Check that "type" is a 'ConI', 'ConP', ...
// When at correct component, get corresponding Operand
if ( index == 0 ) {
}
// Decrement number of constants to go
--index;
}
}
}
// Did not find a constant for this index.
return NULL;
}
// If this operand has a single ideal type, return its type
return type;
}
}
// "true" if this operand is a simple type that is swallowed
return true;
}
return false;
}
// Output code to access the value of the index'th constant
uint const_index) {
switch(dtype) {
default:
assert( false, "ShouldNotReachHere()");
}
}
}
}
//------------------------------Constraint-------------------------------------
}
}
}
}
}
//------------------------------Predicate--------------------------------------
}
}
}
}
//------------------------------Interface--------------------------------------
}
}
return Form::no_interface;
}
return NULL;
return (RegInterface*)this;
}
return (MemInterface*)this;
}
return (ConstInterface*)this;
}
return (CondInterface*)this;
}
}
// Write info to output files
}
//------------------------------RegInterface-----------------------------------
}
RegInterface::~RegInterface() {
}
}
// Write info to output files
}
//------------------------------ConstInterface---------------------------------
}
ConstInterface::~ConstInterface() {
}
}
// Write info to output files
}
//------------------------------MemInterface-----------------------------------
}
MemInterface::~MemInterface() {
// not owner of any character arrays
}
}
// Write info to output files
// fprintf(fp,"\n");
}
//------------------------------CondInterface----------------------------------
const char* not_equal, const char* not_equal_format,
const char* less, const char* less_format,
const char* greater_equal, const char* greater_equal_format,
const char* less_equal, const char* less_equal_format,
const char* greater, const char* greater_format)
: Interface("COND_INTER"),
}
CondInterface::~CondInterface() {
// not owner of any character arrays
}
}
// Write info to output files
// fprintf(fp,"\n");
}
//------------------------------ConstructRule----------------------------------
: _construct(cnstr) {
}
ConstructRule::~ConstructRule() {
}
}
}
//==============================Shared Forms===================================
//------------------------------AttributeForm----------------------------------
}
}
else assert( false,"");
}
AttributeForm::~AttributeForm() {
}
// Dynamic type check
return (AttributeForm*)this;
}
// inlined // int AttributeForm::type() { return id;}
}
}
else {
}
}
//------------------------------Component--------------------------------------
}
}
// True if this component is equal to the parameter.
return (_usedef == use_def_kill_enum ? true : false);
}
}
_usedef |= new_use_def;
return _usedef;
}
// Check the base type of this component, if it has one
}
}
}
//------------------------------ComponentList---------------------------------
}
ComponentList::~ComponentList() {
// // This list may not own its elements if copied via assignment
// Component *component;
// for (reset(); (component = iter()) != NULL;) {
// delete component;
// }
}
}
bool mflag) {
}
return NULL;
}
// At end of list?
return comp;
}
// In post-match components?
return comp;
}
return post_match_iter();
}
// Shortcut complete iteration if there are not enough entries
int index = 0;
return component;
}
++index;
}
return NULL;
}
PreserveIter pi(this);
reset();
}
return NULL;
}
// Return number of USEs + number of DEFs
// When there are no components, or the first component is a USE,
// then we add '1' to hold a space for the 'result' operand.
PreserveIter pi(this);
++count;
}
}
return count;
}
// Return zero-based position of operand 'name' in list; -1 if not in list.
// if parameter 'usedef' is ::USE, it will match USE, USE_DEF, ...
PreserveIter pi(this);
int position = 0;
// When the first component is not a DEF,
// leave space for the result operand!
++position;
++num_opnds;
}
// When the first entry in the component list is a DEF and a USE
// Treat them as being separate, a DEF first, then a USE
if( position==0
return position+1;
} else {
}
}
return position;
}
}
++position;
}
}
}
}
return Not_in_list;
}
PreserveIter pi(this);
int position = 0;
// When the first component is not a DEF,
// leave space for the result operand!
++position;
}
return position;
}
++position;
}
}
return Not_in_list;
}
PreserveIter pi(this);
}
PreserveIter pi(this);
int position = 0;
reset();
// When the first component is not a DEF,
// leave space for the result operand!
++position;
}
return position;
}
++position;
}
}
return -1;
}
PreserveIter pi(this);
int position = 0;
reset();
// When the first component is not a DEF,
// leave space for the result operand!
++position;
}
return position;
}
++position;
}
}
return -1;
}
PreserveIter pi(this);
}
}
//------------------------------MatchNode--------------------------------------
_commutative_id(0) {
}
}
} else {
}
} else {
}
}
// // This node may not own its children if copied via assignment
// if( _lChild ) delete _lChild;
// if( _rChild ) delete _rChild;
}
return true;
} else {
++position;
}
return false;
}
// Recursive call collecting info on top-level operands, not transitive.
// Implementation does not modify state of internal structures.
bool def_flag) const {
// Base case
// If _opType is not an operation, do not build a component for it #####
if( f != NULL ) {
// Add non-ideals that are operands, operand-classes,
if( ! f->ideal_only()
&& (f->is_opclass() || f->is_operand()) ) {
}
}
return;
}
// Promote results of "Set" to DEF
tmpdef_flag = false; // only applies to component immediately following 'Set'
}
// Find the n'th base-operand in the match node,
// recursively investigates match rules of user-defined operands.
//
// Implementation does not modify state of internal structures since they
// can be shared.
const char * &opType) const {
// Base case
// Check for special case: "Universe", "label"
if (position == 0) {
return 1;
} else {
-- position;
return 0;
}
}
// Check for user-defined type
if (form) {
// User operand or instruction?
if ( opForm ) {
} else if ( inForm ) {
}
}
// if this is user-defined, recurse on match rule
// User-defined operand and instruction forms have a match-rule.
if (matchNode) {
} else {
// Either not a form, or a system-defined form (no match rule).
if (position==0) {
return 1;
} else {
--position;
return 0;
}
}
} else {
// Examine the left child and right child as well
if (_lChild) {
return 1;
}
if (_rChild) {
return 1;
}
}
return 0;
}
// Recursive call on all operands' match rules in my match rule.
const char *result;
const char *name;
const char *opType;
++index;
}
return num_consts;
}
// Recursive call on all operands' match rules in my match rule.
// Constants in match rule subtree with specified type
const char *result;
const char *name;
const char *opType;
++index;
}
return num_consts;
}
// Recursive call on all operands' match rules in my match rule.
}
}
// If there is no right reduction, return NULL.
// If we are a "Set", start from the right child.
(const MatchNode *)this;
// If our right child exists, it is the right reduction
}
// Else, May be simple chain rule: (Set dst operand_form), rightStr=NULL;
return rightStr;
}
// If there is no left reduction, return NULL.
// If we are a "Set", start from the right child.
(const MatchNode *)this;
// If our left child exists, it is the left reduction
} else {
// May be simple chain rule: (Set dst operand_form_source)
if ( sets_result() ) {
if( oper ) {
}
}
}
return leftStr;
}
//------------------------------count_instr_names------------------------------
// Count occurrences of operands names in the leaves of the instruction
// match rule.
if( !this ) return;
cnt++; // One more name found
}
}
//------------------------------build_instr_pred-------------------------------
// Build a path to 'name' in buf. Actually only build if cnt is zero, so we
// can skip some leading instances of 'name'.
if( _lChild ) {
}
if( _rChild ) {
}
// Wrong name? Give up...
return cnt-1;
}
return cnt;
}
//------------------------------build_internalop-------------------------------
// Build string representation of subtree
// Build string representation of subtree
// Operation lchildType rchildType
// Hash the subtree string in _internalOps; if a name exists, use it
// Else create a unique name, and add it to the hash table
}
// Add the internal operand name to the MatchNode
_internalop = iop;
}
}
}
else {
}
}
static const char *needs_ideal_memory_list[] = {
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
"StoreB","StoreC","Store" ,"StoreFP",
"LoadI", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
"StoreVector", "LoadVector",
"LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",
"LoadPLocked",
"StorePConditional", "StoreIConditional", "StoreLConditional",
"CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN",
"StoreCM",
"ClearArray",
"GetAndAddI", "GetAndSetI", "GetAndSetP",
"GetAndAddL", "GetAndSetL", "GetAndSetN",
};
return 1;
if( _lChild ) {
for( int i=0; i<cnt; i++ )
return 1;
return 1;
}
if( _rChild ) {
for( int i=0; i<cnt; i++ )
return 1;
return 1;
}
return 0;
}
// TRUE if defines a derived oop, and so needs a base oop edge present
// post-matching.
}
if( is_simple_chain_rule(globals) ) {
} // Else check instruction
}
//-------------------------cisc spilling methods-------------------------------
// helper routines and methods for detecting cisc-spilling instructions
//-------------------------cisc_spill_merge------------------------------------
// Combine results of left and right checks
// neither side is spillable, nor prevents cisc spilling
}
// right side is spillable
}
// left side is spillable
}
// left or right prevents cisc spilling this instruction
}
else {
// Only allow one to spill
}
return cisc_spillable;
}
//-------------------------root_ops_match--------------------------------------
// Base Case: check that the current operands/operations match
}
//-------------------------cisc_spill_match_node-------------------------------
// Recursively check two MatchRules for legal conversion via cisc-spilling
int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* ®_type) {
// Check that each has same number of operands at this level
return Not_cisc_spillable;
// Base Case: check that the current operands/operations match
// or are CISC spillable
} else {
if (form->is_operand()) {
// Make sure the loadX matches the type of the reg
}
// Detect reg vs (loadX memory)
&& form2_inst
return Is_cisc_spillable;
} else {
}
}
// Detect reg vs memory
return Is_cisc_spillable;
} else {
}
}
// If cisc is still possible, check rest of tree
if( cisc_spillable == Maybe_cisc_spillable ) {
// Check that each has same number of operands at this level
// Check left operands
} else {
}
// Check right operands
} else {
right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type);
}
// Combine results of left and right checks
}
return cisc_spillable;
}
//---------------------------cisc_spill_match_rule------------------------------
// Recursively check two MatchRules for legal conversion via cisc-spilling
// This method handles the root of Match tree,
// general recursive checks done in MatchNode
const char* ®_type) {
// Check that each sets a result
// Check that each has same number of operands at this level
// Check left operands: at root, must be target of 'Set'
} else {
// Do not support cisc-spilling instruction's target location
} else {
}
}
// Check right operands: recursive walk to identify reg->mem operand
} else {
right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type);
}
// Combine results of left and right checks
return cisc_spillable;
}
//----------------------------- equivalent ------------------------------------
// Recursively check to see if two match rules are equivalent.
// This rule handles the root.
// Check that each sets a result
return false;
}
// Check that the current operands/operations match
return false;
}
if (_lChild ) {
return false;
return false; // I have NULL left child, mRule2 has non-NULL left child.
}
if (_rChild ) {
return false;
return false; // I have NULL right child, mRule2 has non-NULL right child.
}
// We've made it through the gauntlet.
return true;
}
//----------------------------- equivalent ------------------------------------
// Recursively check to see if two match rules are equivalent.
// This rule handles the operands.
if( !mNode2 )
return false;
// Check that the current operands/operations match
return false;
}
// Check that their children also match
if (_lChild ) {
return false;
return false; // I have NULL left child, mNode2 has non-NULL left child.
}
if (_rChild ) {
return false;
return false; // I have NULL right child, mNode2 has non-NULL right child.
}
// We've made it through the gauntlet.
return true;
}
//-------------------------- has_commutative_op -------------------------------
// Recursively check for commutative operations with subtree operands
// which could be swapped.
static const char *commut_op_list[] = {
"AddI","AddL","AddF","AddD",
"AndI","AndL",
"MaxI","MinI",
"MulI","MulL","MulF","MulD",
"OrI" ,"OrL" ,
"XorI","XorL"
};
// Don't swap if right operand is an immediate constant.
bool is_const = false;
if ( form ) {
is_const = true;
}
}
if( !is_const ) {
for( int i=0; i<cnt; i++ ) {
count++;
break;
}
}
}
}
if( _lChild )
if( _rChild )
}
//-------------------------- swap_commutative_op ------------------------------
// Recursively swap specified commutative operation with subtree operands.
"not swappable operation");
// Don't exit here since we need to build internalop.
}
if( _lChild )
if( _rChild )
// If not the root, reduce this subtree to an internal operand
}
}
//-------------------------- swap_commutative_op ------------------------------
// Recursively swap specified commutative operation with subtree operands.
void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) {
// Clone
// Swap operands of commutative operation
if( (--count) > 0 ) {
}
}
//------------------------------MatchRule--------------------------------------
}
}
int numleaves)
_numchilds(0) {
delete mroot;
}
}
// Recursive call collecting info on top-level operands, not transitive.
// Implementation does not modify state of internal structures.
void MatchRule::append_components(FormDict& locals, ComponentList& components, bool def_flag) const {
false /* not necessarily a def */);
}
// Recursive call on all operands' match rules in my match rule.
// Implementation does not modify state of internal structures since they
// can be shared.
// The MatchNode that is called first treats its
const char * &opType)const{
}
position = 0;
return 1;
}
}
return 0;
}
position = 0;
return ideal_to_const_type(opType);
}
}
}
// Check for chain rule, and do not generate a match list for it
// If this is ideal, then it is a base match, not a chain rule.
return true;
}
}
// Check for "Set" form of chain rule, and do not generate a match list
if (_rChild) {
return true;
}
}
return false;
}
if( _rChild ) {
#if 1
return 1;
#else
return 1;
// Do not treat *CastPP this way, because it
// may transfer a raw pointer to an oop.
// If the register allocator were to coalesce this
// into a single LRG, the GC maps would be incorrect.
//if( strcmp(opType,"CastPP")==0 )
// return 1;
//if( strcmp(opType,"CheckCastPP")==0 )
// return 1;
//
// Do not treat CastX2P or CastP2X this way, because
// raw pointers and int types are treated differently
// when saving local & stack info for safepoints in
// Output().
//if( strcmp(opType,"CastX2P")==0 )
// return 1;
//if( strcmp(opType,"CastP2X")==0 )
// return 1;
#endif
}
return 1;
return 0;
}
if( _rChild ) {
0 /* 0 to line up columns nicely */ )
return 1;
}
return 0;
}
if( !_opType ) return false;
return
}
}
return false;
}
if( !_opType ) return false;
return
}
}
return false;
}
}
return false;
}
bool ideal_goto = false;
ideal_goto = true;
}
return ideal_goto;
}
if( _opType ) {
return true;
}
return false;
}
if( _opType ) {
return true;
}
return false;
}
}
return ideal_load;
}
static const char *vector_list[] = {
"AddVB","AddVS","AddVI","AddVL","AddVF","AddVD",
"SubVB","SubVS","SubVI","SubVL","SubVF","SubVD",
"MulVS","MulVI","MulVF","MulVD",
"DivVF","DivVD",
"AndV" ,"XorV" ,"OrV",
"LShiftCntV","RShiftCntV",
"LShiftVB","LShiftVS","LShiftVI","LShiftVL",
"RShiftVB","RShiftVS","RShiftVI","RShiftVL",
"URShiftVB","URShiftVS","URShiftVI","URShiftVL",
"ReplicateB","ReplicateS","ReplicateI","ReplicateL","ReplicateF","ReplicateD",
"LoadVector","StoreVector",
// Next are not supported currently.
"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",
"ExtractB","ExtractUB","ExtractC","ExtractS","ExtractI","ExtractL","ExtractF","ExtractD"
};
if (_rChild) {
for (int i=0; i<cnt; i++)
return true;
}
return false;
}
// Some loads operate on what is effectively immutable memory so we
// should skip the anti dep computations. For some of these nodes
// the rewritable field keeps the anti dep logic from triggering but
// for certain kinds of LoadKlass it does not since they are
// actually reading memory which could be rewritten by the runtime,
// though never by generated code. This disables it uniformly for
// the nodes that behave like this: LoadKlass, LoadNKlass and
// LoadRange.
return true;
}
}
return false;
}
}
return ideal_store;
}
}
// Write just one line.
}
}
//------------------------------Attribute--------------------------------------
}
}
// Make sure it is an integer constant:
int result = 0;
}
return result;
}
} // Debug printer
// Write to output files
}
//------------------------------FormatRule----------------------------------
}
FormatRule::~FormatRule() {
}
}
// Write to output files
}