Merge
This commit is contained in:
commit
fa597af116
@ -1034,6 +1034,11 @@ int Compile::ConstantTable::calculate_table_base_offset() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
|
||||
void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||
Compile* C = ra_->C;
|
||||
Compile::ConstantTable& constant_table = C->constant_table();
|
||||
@ -1884,6 +1889,9 @@ const int Matcher::float_cmove_cost() {
|
||||
return (VM_Version::is_T4() || VM_Version::is_sparc64()) ? ConditionalMoveLimit : 0;
|
||||
}
|
||||
|
||||
// Does the CPU require late expand (see block.cpp for description of late expand)?
|
||||
const bool Matcher::require_postalloc_expand = false;
|
||||
|
||||
// Should the Matcher clone shifts on addressing modes, expecting them to
|
||||
// be subsumed into complex addressing expressions or compute them into
|
||||
// registers? True for Intel but false for most RISCs
|
||||
|
@ -487,6 +487,11 @@ int Compile::ConstantTable::calculate_table_base_offset() const {
|
||||
return 0; // absolute addressing, no offset
|
||||
}
|
||||
|
||||
bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
|
||||
void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||
// Empty encoding
|
||||
}
|
||||
@ -1389,6 +1394,9 @@ const int Matcher::long_cmove_cost() { return 1; }
|
||||
// No CMOVF/CMOVD with SSE/SSE2
|
||||
const int Matcher::float_cmove_cost() { return (UseSSE>=1) ? ConditionalMoveLimit : 0; }
|
||||
|
||||
// Does the CPU require late expand (see block.cpp for description of late expand)?
|
||||
const bool Matcher::require_postalloc_expand = false;
|
||||
|
||||
// Should the Matcher clone shifts on addressing modes, expecting them to
|
||||
// be subsumed into complex addressing expressions or compute them into
|
||||
// registers? True for Intel but false for most RISCs
|
||||
|
@ -688,6 +688,11 @@ int Compile::ConstantTable::calculate_table_base_offset() const {
|
||||
return 0; // absolute addressing, no offset
|
||||
}
|
||||
|
||||
bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
|
||||
void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||
// Empty encoding
|
||||
}
|
||||
@ -1542,6 +1547,9 @@ const int Matcher::long_cmove_cost() { return 0; }
|
||||
// No CMOVF/CMOVD with SSE2
|
||||
const int Matcher::float_cmove_cost() { return ConditionalMoveLimit; }
|
||||
|
||||
// Does the CPU require late expand (see block.cpp for description of late expand)?
|
||||
const bool Matcher::require_postalloc_expand = false;
|
||||
|
||||
// Should the Matcher clone shifts on addressing modes, expecting them
|
||||
// to be subsumed into complex addressing expressions or compute them
|
||||
// into registers? True for Intel but false for most RISCs
|
||||
|
@ -219,19 +219,21 @@ void ADLParser::instr_parse(void) {
|
||||
else if (!strcmp(ident, "encode")) {
|
||||
parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
|
||||
}
|
||||
else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);
|
||||
else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
|
||||
else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
|
||||
else if (!strcmp(ident, "effect")) effect_parse(instr);
|
||||
else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
|
||||
else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
|
||||
else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);
|
||||
// Parse late expand keyword.
|
||||
else if (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr);
|
||||
else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
|
||||
else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
|
||||
else if (!strcmp(ident, "effect")) effect_parse(instr);
|
||||
else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
|
||||
else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
|
||||
else if (!strcmp(ident, "constraint")) {
|
||||
parse_err(SYNERR, "Instructions do not specify a constraint\n");
|
||||
}
|
||||
else if (!strcmp(ident, "construct")) {
|
||||
parse_err(SYNERR, "Instructions do not specify a construct\n");
|
||||
}
|
||||
else if (!strcmp(ident, "format")) instr->_format = format_parse();
|
||||
else if (!strcmp(ident, "format")) instr->_format = format_parse();
|
||||
else if (!strcmp(ident, "interface")) {
|
||||
parse_err(SYNERR, "Instructions do not specify an interface\n");
|
||||
}
|
||||
@ -240,13 +242,14 @@ void ADLParser::instr_parse(void) {
|
||||
// Check identifier to see if it is the name of an attribute
|
||||
const Form *form = _globalNames[ident];
|
||||
AttributeForm *attr = form ? form->is_attribute() : NULL;
|
||||
if( attr && (attr->_atype == INS_ATTR) ) {
|
||||
if (attr && (attr->_atype == INS_ATTR)) {
|
||||
// Insert the new attribute into the linked list.
|
||||
Attribute *temp = attr_parse(ident);
|
||||
temp->_next = instr->_attribs;
|
||||
instr->_attribs = temp;
|
||||
} else {
|
||||
parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of an instruction attribute at %s\n", ident);
|
||||
parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of"
|
||||
" an instruction attribute at %s\n", ident);
|
||||
}
|
||||
}
|
||||
skipws();
|
||||
@ -258,13 +261,17 @@ void ADLParser::instr_parse(void) {
|
||||
}
|
||||
// Check for "Set" form of chain rule
|
||||
adjust_set_rule(instr);
|
||||
if (_AD._pipeline ) {
|
||||
if( instr->expands() ) {
|
||||
if( instr->_ins_pipe )
|
||||
parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\"; ins_pipe will be unused\n", instr->_ident);
|
||||
if (_AD._pipeline) {
|
||||
// No pipe required for late expand.
|
||||
if (instr->expands() || instr->postalloc_expands()) {
|
||||
if (instr->_ins_pipe) {
|
||||
parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\";"
|
||||
" ins_pipe will be unused\n", instr->_ident);
|
||||
}
|
||||
} else {
|
||||
if( !instr->_ins_pipe )
|
||||
if (!instr->_ins_pipe) {
|
||||
parse_err(WARN, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add instruction to tail of instruction list
|
||||
@ -2779,11 +2786,13 @@ void ADLParser::ins_encode_parse_block(InstructForm& inst) {
|
||||
encoding->add_parameter(opForm->_ident, param);
|
||||
}
|
||||
|
||||
// Define a MacroAssembler instance for use by the encoding. The
|
||||
// name is chosen to match the __ idiom used for assembly in other
|
||||
// parts of hotspot and assumes the existence of the standard
|
||||
// #define __ _masm.
|
||||
encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
|
||||
if (!inst._is_postalloc_expand) {
|
||||
// Define a MacroAssembler instance for use by the encoding. The
|
||||
// name is chosen to match the __ idiom used for assembly in other
|
||||
// parts of hotspot and assumes the existence of the standard
|
||||
// #define __ _masm.
|
||||
encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
|
||||
}
|
||||
|
||||
// Parse the following %{ }% block
|
||||
ins_encode_parse_block_impl(inst, encoding, ec_name);
|
||||
@ -2857,7 +2866,8 @@ void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encodi
|
||||
inst.set_is_mach_constant(true);
|
||||
|
||||
if (_curchar == '(') {
|
||||
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument (only constantaddress and constantoffset)", ec_name);
|
||||
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
|
||||
"(only constantaddress and constantoffset)", ec_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -3050,6 +3060,157 @@ void ADLParser::ins_encode_parse(InstructForm& inst) {
|
||||
inst._insencode = encrule;
|
||||
}
|
||||
|
||||
//------------------------------postalloc_expand_parse---------------------------
|
||||
// Encode rules have the form
|
||||
// postalloc_expand( encode_class_name(parameter_list) );
|
||||
//
|
||||
// The "encode_class_name" must be defined in the encode section.
|
||||
// The parameter list contains $names that are locals.
|
||||
//
|
||||
// This is just a copy of ins_encode_parse without the loop.
|
||||
void ADLParser::postalloc_expand_parse(InstructForm& inst) {
|
||||
inst._is_postalloc_expand = true;
|
||||
|
||||
// Parse encode class name.
|
||||
skipws(); // Skip whitespace.
|
||||
if (_curchar != '(') {
|
||||
// Check for postalloc_expand %{ form
|
||||
if ((_curchar == '%') && (*(_ptr+1) == '{')) {
|
||||
next_char(); // Skip '%'
|
||||
next_char(); // Skip '{'
|
||||
|
||||
// Parse the block form of postalloc_expand
|
||||
ins_encode_parse_block(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_err(SYNERR, "missing '(' in postalloc_expand definition\n");
|
||||
return;
|
||||
}
|
||||
next_char(); // Move past '('.
|
||||
skipws();
|
||||
|
||||
InsEncode *encrule = new InsEncode(); // Encode class for instruction.
|
||||
encrule->_linenum = linenum();
|
||||
char *ec_name = NULL; // String representation of encode rule.
|
||||
// identifier is optional.
|
||||
if (_curchar != ')') {
|
||||
ec_name = get_ident();
|
||||
if (ec_name == NULL) {
|
||||
parse_err(SYNERR, "Invalid postalloc_expand class name after 'postalloc_expand('.\n");
|
||||
return;
|
||||
}
|
||||
// Check that encoding is defined in the encode section.
|
||||
EncClass *encode_class = _AD._encode->encClass(ec_name);
|
||||
|
||||
// Get list for encode method's parameters
|
||||
NameAndList *params = encrule->add_encode(ec_name);
|
||||
|
||||
// Parse the parameters to this encode method.
|
||||
skipws();
|
||||
if (_curchar == '(') {
|
||||
next_char(); // Move past '(' for parameters.
|
||||
|
||||
// Parse the encode method's parameters.
|
||||
while (_curchar != ')') {
|
||||
char *param = get_ident_or_literal_constant("encoding operand");
|
||||
if (param != NULL) {
|
||||
// Found a parameter:
|
||||
|
||||
// First check for constant table support.
|
||||
|
||||
// Check if this instruct is a MachConstantNode.
|
||||
if (strcmp(param, "constanttablebase") == 0) {
|
||||
// This instruct is a MachConstantNode.
|
||||
inst.set_is_mach_constant(true);
|
||||
|
||||
if (_curchar == '(') {
|
||||
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
|
||||
"(only constantaddress and constantoffset)", ec_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ((strcmp(param, "constantaddress") == 0) ||
|
||||
(strcmp(param, "constantoffset") == 0)) {
|
||||
// This instruct is a MachConstantNode.
|
||||
inst.set_is_mach_constant(true);
|
||||
|
||||
// If the constant keyword has an argument, parse it.
|
||||
if (_curchar == '(') constant_parse(inst);
|
||||
}
|
||||
|
||||
// Else check it is a local name, add it to the list, then check for more.
|
||||
// New: allow hex constants as parameters to an encode method.
|
||||
// New: allow parenthesized expressions as parameters.
|
||||
// New: allow "primary", "secondary", "tertiary" as parameters.
|
||||
// New: allow user-defined register name as parameter.
|
||||
else if ((inst._localNames[param] == NULL) &&
|
||||
!ADLParser::is_literal_constant(param) &&
|
||||
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
|
||||
((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {
|
||||
parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
|
||||
return;
|
||||
}
|
||||
params->add_entry(param);
|
||||
|
||||
skipws();
|
||||
if (_curchar == ',') {
|
||||
// More parameters to come.
|
||||
next_char(); // Move past ',' between parameters.
|
||||
skipws(); // Skip to next parameter.
|
||||
} else if (_curchar == ')') {
|
||||
// Done with parameter list
|
||||
} else {
|
||||
// Only ',' or ')' are valid after a parameter name.
|
||||
parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", ec_name);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
skipws();
|
||||
// Did not find a parameter.
|
||||
if (_curchar == ',') {
|
||||
parse_err(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);
|
||||
return;
|
||||
}
|
||||
if (_curchar != ')') {
|
||||
parse_err(SYNERR, "Expected ')' after postalloc_expand parameters.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // WHILE loop collecting parameters.
|
||||
next_char(); // Move past ')' at end of parameters.
|
||||
} // Done with parameter list for encoding.
|
||||
|
||||
// Check for ',' or ')' after encoding.
|
||||
skipws(); // Move to character after parameters.
|
||||
if (_curchar != ')') {
|
||||
// Only a ')' is allowed.
|
||||
parse_err(SYNERR, "Expected ')' after postalloc_expand %s.\n", ec_name);
|
||||
return;
|
||||
}
|
||||
} // Done parsing postalloc_expand method and their parameters.
|
||||
if (_curchar != ')') {
|
||||
parse_err(SYNERR, "Missing ')' at end of postalloc_expand description.\n");
|
||||
return;
|
||||
}
|
||||
next_char(); // Move past ')'.
|
||||
skipws(); // Skip leading whitespace.
|
||||
|
||||
if (_curchar != ';') {
|
||||
parse_err(SYNERR, "Missing ';' at end of postalloc_expand.\n");
|
||||
return;
|
||||
}
|
||||
next_char(); // Move past ';'.
|
||||
skipws(); // Be friendly to oper_parse().
|
||||
|
||||
// Debug Stuff.
|
||||
if (_AD._adl_debug > 1) fprintf(stderr, "Instruction postalloc_expand: %s\n", ec_name);
|
||||
|
||||
// Set encode class of this instruction.
|
||||
inst._insencode = encrule;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------constant_parse---------------------------------
|
||||
// Parse a constant expression.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -159,6 +159,8 @@ protected:
|
||||
void ins_encode_parse(InstructForm &inst);
|
||||
void ins_encode_parse_block(InstructForm &inst);
|
||||
void ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name);
|
||||
// Parse instruction postalloc expand rule.
|
||||
void postalloc_expand_parse(InstructForm &inst);
|
||||
|
||||
void constant_parse(InstructForm& inst);
|
||||
void constant_parse_expression(EncClass* encoding, char* ec_name);
|
||||
|
@ -311,6 +311,8 @@ public:
|
||||
void defineEvalConstant(FILE *fp, InstructForm &node);
|
||||
// Generator for Emit methods for instructions
|
||||
void defineEmit (FILE *fp, InstructForm &node);
|
||||
// Generator for postalloc_expand methods for instructions.
|
||||
void define_postalloc_expand(FILE *fp, InstructForm &node);
|
||||
|
||||
// Define a MachOper encode method
|
||||
void define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,
|
||||
|
@ -36,27 +36,28 @@ InstructForm::InstructForm(const char *id, bool ideal_only)
|
||||
{
|
||||
_ftype = Form::INS;
|
||||
|
||||
_matrule = NULL;
|
||||
_insencode = NULL;
|
||||
_constant = NULL;
|
||||
_opcode = NULL;
|
||||
_size = NULL;
|
||||
_attribs = NULL;
|
||||
_predicate = NULL;
|
||||
_exprule = NULL;
|
||||
_rewrule = NULL;
|
||||
_format = NULL;
|
||||
_peephole = NULL;
|
||||
_ins_pipe = NULL;
|
||||
_uniq_idx = NULL;
|
||||
_num_uniq = 0;
|
||||
_cisc_spill_operand = Not_cisc_spillable;// Which operand may cisc-spill
|
||||
_matrule = NULL;
|
||||
_insencode = NULL;
|
||||
_constant = NULL;
|
||||
_is_postalloc_expand = false;
|
||||
_opcode = NULL;
|
||||
_size = NULL;
|
||||
_attribs = NULL;
|
||||
_predicate = NULL;
|
||||
_exprule = NULL;
|
||||
_rewrule = NULL;
|
||||
_format = NULL;
|
||||
_peephole = NULL;
|
||||
_ins_pipe = NULL;
|
||||
_uniq_idx = NULL;
|
||||
_num_uniq = 0;
|
||||
_cisc_spill_operand = Not_cisc_spillable;// Which operand may cisc-spill
|
||||
_cisc_spill_alternate = NULL; // possible cisc replacement
|
||||
_cisc_reg_mask_name = NULL;
|
||||
_is_cisc_alternate = false;
|
||||
_is_short_branch = false;
|
||||
_short_branch_form = NULL;
|
||||
_alignment = 1;
|
||||
_cisc_reg_mask_name = NULL;
|
||||
_is_cisc_alternate = false;
|
||||
_is_short_branch = false;
|
||||
_short_branch_form = NULL;
|
||||
_alignment = 1;
|
||||
}
|
||||
|
||||
InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
|
||||
@ -68,27 +69,28 @@ InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
|
||||
{
|
||||
_ftype = Form::INS;
|
||||
|
||||
_matrule = rule;
|
||||
_insencode = instr->_insencode;
|
||||
_constant = instr->_constant;
|
||||
_opcode = instr->_opcode;
|
||||
_size = instr->_size;
|
||||
_attribs = instr->_attribs;
|
||||
_predicate = instr->_predicate;
|
||||
_exprule = instr->_exprule;
|
||||
_rewrule = instr->_rewrule;
|
||||
_format = instr->_format;
|
||||
_peephole = instr->_peephole;
|
||||
_ins_pipe = instr->_ins_pipe;
|
||||
_uniq_idx = instr->_uniq_idx;
|
||||
_num_uniq = instr->_num_uniq;
|
||||
_cisc_spill_operand = Not_cisc_spillable;// Which operand may cisc-spill
|
||||
_cisc_spill_alternate = NULL; // possible cisc replacement
|
||||
_cisc_reg_mask_name = NULL;
|
||||
_is_cisc_alternate = false;
|
||||
_is_short_branch = false;
|
||||
_short_branch_form = NULL;
|
||||
_alignment = 1;
|
||||
_matrule = rule;
|
||||
_insencode = instr->_insencode;
|
||||
_constant = instr->_constant;
|
||||
_is_postalloc_expand = instr->_is_postalloc_expand;
|
||||
_opcode = instr->_opcode;
|
||||
_size = instr->_size;
|
||||
_attribs = instr->_attribs;
|
||||
_predicate = instr->_predicate;
|
||||
_exprule = instr->_exprule;
|
||||
_rewrule = instr->_rewrule;
|
||||
_format = instr->_format;
|
||||
_peephole = instr->_peephole;
|
||||
_ins_pipe = instr->_ins_pipe;
|
||||
_uniq_idx = instr->_uniq_idx;
|
||||
_num_uniq = instr->_num_uniq;
|
||||
_cisc_spill_operand = Not_cisc_spillable; // Which operand may cisc-spill
|
||||
_cisc_spill_alternate = NULL; // possible cisc replacement
|
||||
_cisc_reg_mask_name = NULL;
|
||||
_is_cisc_alternate = false;
|
||||
_is_short_branch = false;
|
||||
_short_branch_form = NULL;
|
||||
_alignment = 1;
|
||||
// Copy parameters
|
||||
const char *name;
|
||||
instr->_parameters.reset();
|
||||
@ -157,6 +159,11 @@ bool InstructForm::expands() const {
|
||||
return ( _exprule != NULL );
|
||||
}
|
||||
|
||||
// This instruction has a late expand rule?
|
||||
bool InstructForm::postalloc_expands() const {
|
||||
return _is_postalloc_expand;
|
||||
}
|
||||
|
||||
// This instruction has a peephole rule?
|
||||
Peephole *InstructForm::peepholes() const {
|
||||
return _peephole;
|
||||
|
@ -88,30 +88,31 @@ private:
|
||||
|
||||
public:
|
||||
// Public Data
|
||||
const char *_ident; // Name of this instruction
|
||||
NameList _parameters; // Locally defined names
|
||||
FormDict _localNames; // Table of operands & their types
|
||||
MatchRule *_matrule; // Matching rule for this instruction
|
||||
Opcode *_opcode; // Encoding of the opcode for instruction
|
||||
char *_size; // Size of instruction
|
||||
InsEncode *_insencode; // Encoding class instruction belongs to
|
||||
InsEncode *_constant; // Encoding class constant value belongs to
|
||||
Attribute *_attribs; // List of Attribute rules
|
||||
Predicate *_predicate; // Predicate test for this instruction
|
||||
FormDict _effects; // Dictionary of effect rules
|
||||
ExpandRule *_exprule; // Expand rule for this instruction
|
||||
RewriteRule *_rewrule; // Rewrite rule for this instruction
|
||||
FormatRule *_format; // Format for assembly generation
|
||||
Peephole *_peephole; // List of peephole rules for instruction
|
||||
const char *_ins_pipe; // Instruction Scheduling description class
|
||||
const char *_ident; // Name of this instruction
|
||||
NameList _parameters; // Locally defined names
|
||||
FormDict _localNames; // Table of operands & their types
|
||||
MatchRule *_matrule; // Matching rule for this instruction
|
||||
Opcode *_opcode; // Encoding of the opcode for instruction
|
||||
char *_size; // Size of instruction
|
||||
InsEncode *_insencode; // Encoding class instruction belongs to
|
||||
InsEncode *_constant; // Encoding class constant value belongs to
|
||||
bool _is_postalloc_expand; // Indicates that encoding just does a lateExpand.
|
||||
Attribute *_attribs; // List of Attribute rules
|
||||
Predicate *_predicate; // Predicate test for this instruction
|
||||
FormDict _effects; // Dictionary of effect rules
|
||||
ExpandRule *_exprule; // Expand rule for this instruction
|
||||
RewriteRule *_rewrule; // Rewrite rule for this instruction
|
||||
FormatRule *_format; // Format for assembly generation
|
||||
Peephole *_peephole; // List of peephole rules for instruction
|
||||
const char *_ins_pipe; // Instruction Scheduling description class
|
||||
|
||||
uint *_uniq_idx; // Indexes of unique operands
|
||||
uint _uniq_idx_length; // Length of _uniq_idx array
|
||||
uint _num_uniq; // Number of unique operands
|
||||
ComponentList _components; // List of Components matches MachNode's
|
||||
// operand structure
|
||||
uint *_uniq_idx; // Indexes of unique operands
|
||||
uint _uniq_idx_length; // Length of _uniq_idx array
|
||||
uint _num_uniq; // Number of unique operands
|
||||
ComponentList _components; // List of Components matches MachNode's
|
||||
// operand structure
|
||||
|
||||
bool _has_call; // contain a call and caller save registers should be saved?
|
||||
bool _has_call; // contain a call and caller save registers should be saved?
|
||||
|
||||
// Public Methods
|
||||
InstructForm(const char *id, bool ideal_only = false);
|
||||
@ -133,6 +134,8 @@ public:
|
||||
virtual uint num_defs_or_kills();
|
||||
// This instruction has an expand rule?
|
||||
virtual bool expands() const ;
|
||||
// This instruction has a late expand rule?
|
||||
virtual bool postalloc_expands() const;
|
||||
// Return this instruction's first peephole rule, or NULL
|
||||
virtual Peephole *peepholes() const;
|
||||
// Add a peephole rule to this instruction
|
||||
|
@ -2488,7 +2488,113 @@ void ArchDesc::defineSize(FILE *fp, InstructForm &inst) {
|
||||
fprintf(fp, " return (VerifyOops ? MachNode::size(ra_) : %s);\n", inst._size);
|
||||
|
||||
// (3) and (4)
|
||||
fprintf(fp,"}\n");
|
||||
fprintf(fp,"}\n\n");
|
||||
}
|
||||
|
||||
// Emit late expand function.
|
||||
void ArchDesc::define_postalloc_expand(FILE *fp, InstructForm &inst) {
|
||||
InsEncode *ins_encode = inst._insencode;
|
||||
|
||||
// Output instruction's postalloc_expand prototype.
|
||||
fprintf(fp, "void %sNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {\n",
|
||||
inst._ident);
|
||||
|
||||
assert((_encode != NULL) && (ins_encode != NULL), "You must define an encode section.");
|
||||
|
||||
// Output each operand's offset into the array of registers.
|
||||
inst.index_temps(fp, _globalNames);
|
||||
|
||||
// Output variables "unsigned idx_<par_name>", Node *n_<par_name> and "MachOpnd *op_<par_name>"
|
||||
// for each parameter <par_name> specified in the encoding.
|
||||
ins_encode->reset();
|
||||
const char *ec_name = ins_encode->encode_class_iter();
|
||||
assert(ec_name != NULL, "late expand must specify an encoding");
|
||||
|
||||
EncClass *encoding = _encode->encClass(ec_name);
|
||||
if (encoding == NULL) {
|
||||
fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);
|
||||
abort();
|
||||
}
|
||||
if (ins_encode->current_encoding_num_args() != encoding->num_args()) {
|
||||
globalAD->syntax_err(ins_encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
|
||||
inst._ident, ins_encode->current_encoding_num_args(),
|
||||
ec_name, encoding->num_args());
|
||||
}
|
||||
|
||||
fprintf(fp, " // Access to ins and operands for late expand.\n");
|
||||
const int buflen = 2000;
|
||||
char idxbuf[buflen]; char *ib = idxbuf; sprintf(ib, "");
|
||||
char nbuf [buflen]; char *nb = nbuf; sprintf(nb, "");
|
||||
char opbuf [buflen]; char *ob = opbuf; sprintf(ob, "");
|
||||
|
||||
encoding->_parameter_type.reset();
|
||||
encoding->_parameter_name.reset();
|
||||
const char *type = encoding->_parameter_type.iter();
|
||||
const char *name = encoding->_parameter_name.iter();
|
||||
int param_no = 0;
|
||||
for (; (type != NULL) && (name != NULL);
|
||||
(type = encoding->_parameter_type.iter()), (name = encoding->_parameter_name.iter())) {
|
||||
const char* arg_name = ins_encode->rep_var_name(inst, param_no);
|
||||
int idx = inst.operand_position_format(arg_name);
|
||||
if (strcmp(arg_name, "constanttablebase") == 0) {
|
||||
ib += sprintf(ib, " unsigned idx_%-5s = mach_constant_base_node_input(); \t// %s, \t%s\n",
|
||||
name, type, arg_name);
|
||||
nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);
|
||||
// There is no operand for the constanttablebase.
|
||||
} else if (inst.is_noninput_operand(idx)) {
|
||||
globalAD->syntax_err(inst._linenum,
|
||||
"In %s: you can not pass the non-input %s to a late expand encoding.\n",
|
||||
inst._ident, arg_name);
|
||||
} else {
|
||||
ib += sprintf(ib, " unsigned idx_%-5s = idx%d; \t// %s, \t%s\n",
|
||||
name, idx, type, arg_name);
|
||||
nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);
|
||||
ob += sprintf(ob, " %sOper *op_%s = (%sOper *)opnd_array(%d);\n", type, name, type, idx);
|
||||
}
|
||||
param_no++;
|
||||
}
|
||||
assert(ib < &idxbuf[buflen-1] && nb < &nbuf[buflen-1] && ob < &opbuf[buflen-1], "buffer overflow");
|
||||
|
||||
fprintf(fp, "%s", idxbuf);
|
||||
fprintf(fp, " Node *n_region = lookup(0);\n");
|
||||
fprintf(fp, "%s%s", nbuf, opbuf);
|
||||
fprintf(fp, " Compile *C = ra_->C;\n");
|
||||
|
||||
// Output this instruction's encodings.
|
||||
fprintf(fp, " {");
|
||||
const char *ec_code = NULL;
|
||||
const char *ec_rep_var = NULL;
|
||||
assert(encoding == _encode->encClass(ec_name), "");
|
||||
|
||||
DefineEmitState pending(fp, *this, *encoding, *ins_encode, inst);
|
||||
encoding->_code.reset();
|
||||
encoding->_rep_vars.reset();
|
||||
// Process list of user-defined strings,
|
||||
// and occurrences of replacement variables.
|
||||
// Replacement Vars are pushed into a list and then output.
|
||||
while ((ec_code = encoding->_code.iter()) != NULL) {
|
||||
if (! encoding->_code.is_signal(ec_code)) {
|
||||
// Emit pending code.
|
||||
pending.emit();
|
||||
pending.clear();
|
||||
// Emit this code section.
|
||||
fprintf(fp, "%s", ec_code);
|
||||
} else {
|
||||
// A replacement variable or one of its subfields.
|
||||
// Obtain replacement variable from list.
|
||||
ec_rep_var = encoding->_rep_vars.iter();
|
||||
pending.add_rep_var(ec_rep_var);
|
||||
}
|
||||
}
|
||||
// Emit pending code.
|
||||
pending.emit();
|
||||
pending.clear();
|
||||
fprintf(fp, " }\n");
|
||||
|
||||
fprintf(fp, "}\n\n");
|
||||
|
||||
ec_name = ins_encode->encode_class_iter();
|
||||
assert(ec_name == NULL, "Late expand may only have one encoding.");
|
||||
}
|
||||
|
||||
// defineEmit -----------------------------------------------------------------
|
||||
@ -2841,7 +2947,7 @@ void ArchDesc::define_oper_interface(FILE *fp, OperandForm &oper, FormDict &glob
|
||||
} else if ( (strcmp(name,"disp") == 0) ) {
|
||||
fprintf(fp,"(PhaseRegAlloc *ra_, const Node *node, int idx) const { \n");
|
||||
} else {
|
||||
fprintf(fp,"() const { \n");
|
||||
fprintf(fp, "() const {\n");
|
||||
}
|
||||
|
||||
// Check for hexadecimal value OR replacement variable
|
||||
@ -2891,6 +2997,8 @@ void ArchDesc::define_oper_interface(FILE *fp, OperandForm &oper, FormDict &glob
|
||||
// Hex value
|
||||
fprintf(fp," return %s;\n", encoding);
|
||||
} else {
|
||||
globalAD->syntax_err(oper._linenum, "In operand %s: Do not support this encode constant: '%s' for %s.",
|
||||
oper._ident, encoding, name);
|
||||
assert( false, "Do not support octal or decimal encode constants");
|
||||
}
|
||||
fprintf(fp," }\n");
|
||||
@ -3142,7 +3250,15 @@ void ArchDesc::defineClasses(FILE *fp) {
|
||||
// Ensure this is a machine-world instruction
|
||||
if ( instr->ideal_only() ) continue;
|
||||
|
||||
if (instr->_insencode) defineEmit (fp, *instr);
|
||||
if (instr->_insencode) {
|
||||
if (instr->postalloc_expands()) {
|
||||
// Don't write this to _CPP_EXPAND_file, as the code generated calls C-code
|
||||
// from code sections in ad file that is dumped to fp.
|
||||
define_postalloc_expand(fp, *instr);
|
||||
} else {
|
||||
defineEmit(fp, *instr);
|
||||
}
|
||||
}
|
||||
if (instr->is_mach_constant()) defineEvalConstant(fp, *instr);
|
||||
if (instr->_size) defineSize (fp, *instr);
|
||||
|
||||
|
@ -1633,7 +1633,12 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||
// Output the opcode function and the encode function here using the
|
||||
// encoding class information in the _insencode slot.
|
||||
if ( instr->_insencode ) {
|
||||
fprintf(fp," virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;\n");
|
||||
if (instr->postalloc_expands()) {
|
||||
fprintf(fp," virtual bool requires_postalloc_expand() const { return true; }\n");
|
||||
fprintf(fp," virtual void postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_);\n");
|
||||
} else {
|
||||
fprintf(fp," virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;\n");
|
||||
}
|
||||
}
|
||||
|
||||
// virtual function for getting the size of an instruction
|
||||
|
@ -144,6 +144,10 @@ void Block::find_remove( const Node *n ) {
|
||||
remove_node(find_node(n));
|
||||
}
|
||||
|
||||
bool Block::contains(const Node *n) const {
|
||||
return _nodes.contains(n);
|
||||
}
|
||||
|
||||
// Return empty status of a block. Empty blocks contain only the head, other
|
||||
// ideal nodes, and an optional trailing goto.
|
||||
int Block::is_Empty() const {
|
||||
@ -699,7 +703,7 @@ void PhaseCFG::remove_empty_blocks() {
|
||||
// Fix up the final control flow for basic blocks.
|
||||
void PhaseCFG::fixup_flow() {
|
||||
// Fixup final control flow for the blocks. Remove jump-to-next
|
||||
// block. If neither arm of a IF follows the conditional branch, we
|
||||
// block. If neither arm of an IF follows the conditional branch, we
|
||||
// have to add a second jump after the conditional. We place the
|
||||
// TRUE branch target in succs[0] for both GOTOs and IFs.
|
||||
for (uint i = 0; i < number_of_blocks(); i++) {
|
||||
@ -844,6 +848,228 @@ void PhaseCFG::fixup_flow() {
|
||||
}
|
||||
|
||||
|
||||
// postalloc_expand: Expand nodes after register allocation.
|
||||
//
|
||||
// postalloc_expand has to be called after register allocation, just
|
||||
// before output (i.e. scheduling). It only gets called if
|
||||
// Matcher::require_postalloc_expand is true.
|
||||
//
|
||||
// Background:
|
||||
//
|
||||
// Nodes that are expandend (one compound node requiring several
|
||||
// assembler instructions to be implemented split into two or more
|
||||
// non-compound nodes) after register allocation are not as nice as
|
||||
// the ones expanded before register allocation - they don't
|
||||
// participate in optimizations as global code motion. But after
|
||||
// register allocation we can expand nodes that use registers which
|
||||
// are not spillable or registers that are not allocated, because the
|
||||
// old compound node is simply replaced (in its location in the basic
|
||||
// block) by a new subgraph which does not contain compound nodes any
|
||||
// more. The scheduler called during output can later on process these
|
||||
// non-compound nodes.
|
||||
//
|
||||
// Implementation:
|
||||
//
|
||||
// Nodes requiring postalloc expand are specified in the ad file by using
|
||||
// a postalloc_expand statement instead of ins_encode. A postalloc_expand
|
||||
// contains a single call to an encoding, as does an ins_encode
|
||||
// statement. Instead of an emit() function a postalloc_expand() function
|
||||
// is generated that doesn't emit assembler but creates a new
|
||||
// subgraph. The code below calls this postalloc_expand function for each
|
||||
// node with the appropriate attribute. This function returns the new
|
||||
// nodes generated in an array passed in the call. The old node,
|
||||
// potential MachTemps before and potential Projs after it then get
|
||||
// disconnected and replaced by the new nodes. The instruction
|
||||
// generating the result has to be the last one in the array. In
|
||||
// general it is assumed that Projs after the node expanded are
|
||||
// kills. These kills are not required any more after expanding as
|
||||
// there are now explicitly visible def-use chains and the Projs are
|
||||
// removed. This does not hold for calls: They do not only have
|
||||
// kill-Projs but also Projs defining values. Therefore Projs after
|
||||
// the node expanded are removed for all but for calls. If a node is
|
||||
// to be reused, it must be added to the nodes list returned, and it
|
||||
// will be added again.
|
||||
//
|
||||
// Implementing the postalloc_expand function for a node in an enc_class
|
||||
// is rather tedious. It requires knowledge about many node details, as
|
||||
// the nodes and the subgraph must be hand crafted. To simplify this,
|
||||
// adlc generates some utility variables into the postalloc_expand function,
|
||||
// e.g., holding the operands as specified by the postalloc_expand encoding
|
||||
// specification, e.g.:
|
||||
// * unsigned idx_<par_name> holding the index of the node in the ins
|
||||
// * Node *n_<par_name> holding the node loaded from the ins
|
||||
// * MachOpnd *op_<par_name> holding the corresponding operand
|
||||
//
|
||||
// The ordering of operands can not be determined by looking at a
|
||||
// rule. Especially if a match rule matches several different trees,
|
||||
// several nodes are generated from one instruct specification with
|
||||
// different operand orderings. In this case the adlc generated
|
||||
// variables are the only way to access the ins and operands
|
||||
// deterministically.
|
||||
//
|
||||
// If assigning a register to a node that contains an oop, don't
|
||||
// forget to call ra_->set_oop() for the node.
|
||||
void PhaseCFG::postalloc_expand(PhaseRegAlloc* _ra) {
|
||||
GrowableArray <Node *> new_nodes(32); // Array with new nodes filled by postalloc_expand function of node.
|
||||
GrowableArray <Node *> remove(32);
|
||||
GrowableArray <Node *> succs(32);
|
||||
unsigned int max_idx = C->unique(); // Remember to distinguish new from old nodes.
|
||||
DEBUG_ONLY(bool foundNode = false);
|
||||
|
||||
// for all blocks
|
||||
for (uint i = 0; i < number_of_blocks(); i++) {
|
||||
Block *b = _blocks[i];
|
||||
// For all instructions in the current block.
|
||||
for (uint j = 0; j < b->number_of_nodes(); j++) {
|
||||
Node *n = b->get_node(j);
|
||||
if (n->is_Mach() && n->as_Mach()->requires_postalloc_expand()) {
|
||||
#ifdef ASSERT
|
||||
if (TracePostallocExpand) {
|
||||
if (!foundNode) {
|
||||
foundNode = true;
|
||||
tty->print("POSTALLOC EXPANDING %d %s\n", C->compile_id(),
|
||||
C->method() ? C->method()->name()->as_utf8() : C->stub_name());
|
||||
}
|
||||
tty->print(" postalloc expanding "); n->dump();
|
||||
if (Verbose) {
|
||||
tty->print(" with ins:\n");
|
||||
for (uint k = 0; k < n->len(); ++k) {
|
||||
if (n->in(k)) { tty->print(" "); n->in(k)->dump(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
new_nodes.clear();
|
||||
// Collect nodes that have to be removed from the block later on.
|
||||
uint req = n->req();
|
||||
remove.clear();
|
||||
for (uint k = 0; k < req; ++k) {
|
||||
if (n->in(k) && n->in(k)->is_MachTemp()) {
|
||||
remove.push(n->in(k)); // MachTemps which are inputs to the old node have to be removed.
|
||||
n->in(k)->del_req(0);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether we can allocate enough nodes. We set a fix limit for
|
||||
// the size of postalloc expands with this.
|
||||
uint unique_limit = C->unique() + 40;
|
||||
if (unique_limit >= _ra->node_regs_max_index()) {
|
||||
Compile::current()->record_failure("out of nodes in postalloc expand");
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit (i.e. generate new nodes).
|
||||
n->as_Mach()->postalloc_expand(&new_nodes, _ra);
|
||||
|
||||
assert(C->unique() < unique_limit, "You allocated too many nodes in your postalloc expand.");
|
||||
|
||||
// Disconnect the inputs of the old node.
|
||||
//
|
||||
// We reuse MachSpillCopy nodes. If we need to expand them, there
|
||||
// are many, so reusing pays off. If reused, the node already
|
||||
// has the new ins. n must be the last node on new_nodes list.
|
||||
if (!n->is_MachSpillCopy()) {
|
||||
for (int k = req - 1; k >= 0; --k) {
|
||||
n->del_req(k);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// Check that all nodes have proper operands.
|
||||
for (int k = 0; k < new_nodes.length(); ++k) {
|
||||
if (new_nodes.at(k)->_idx < max_idx || !new_nodes.at(k)->is_Mach()) continue; // old node, Proj ...
|
||||
MachNode *m = new_nodes.at(k)->as_Mach();
|
||||
for (unsigned int l = 0; l < m->num_opnds(); ++l) {
|
||||
if (MachOper::notAnOper(m->_opnds[l])) {
|
||||
outputStream *os = tty;
|
||||
os->print("Node %s ", m->Name());
|
||||
os->print("has invalid opnd %d: %p\n", l, m->_opnds[l]);
|
||||
assert(0, "Invalid operands, see inline trace in hs_err_pid file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Collect succs of old node in remove (for projections) and in succs (for
|
||||
// all other nodes) do _not_ collect projections in remove (but in succs)
|
||||
// in case the node is a call. We need the projections for calls as they are
|
||||
// associated with registes (i.e. they are defs).
|
||||
succs.clear();
|
||||
for (DUIterator k = n->outs(); n->has_out(k); k++) {
|
||||
if (n->out(k)->is_Proj() && !n->is_MachCall() && !n->is_MachBranch()) {
|
||||
remove.push(n->out(k));
|
||||
} else {
|
||||
succs.push(n->out(k));
|
||||
}
|
||||
}
|
||||
// Replace old node n as input of its succs by last of the new nodes.
|
||||
for (int k = 0; k < succs.length(); ++k) {
|
||||
Node *succ = succs.at(k);
|
||||
for (uint l = 0; l < succ->req(); ++l) {
|
||||
if (succ->in(l) == n) {
|
||||
succ->set_req(l, new_nodes.at(new_nodes.length() - 1));
|
||||
}
|
||||
}
|
||||
for (uint l = succ->req(); l < succ->len(); ++l) {
|
||||
if (succ->in(l) == n) {
|
||||
succ->set_prec(l, new_nodes.at(new_nodes.length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Index of old node in block.
|
||||
uint index = b->find_node(n);
|
||||
// Insert new nodes into block and map them in nodes->blocks array
|
||||
// and remember last node in n2.
|
||||
Node *n2 = NULL;
|
||||
for (int k = 0; k < new_nodes.length(); ++k) {
|
||||
n2 = new_nodes.at(k);
|
||||
b->insert_node(n2, ++index);
|
||||
map_node_to_block(n2, b);
|
||||
}
|
||||
|
||||
// Add old node n to remove and remove them all from block.
|
||||
remove.push(n);
|
||||
j--;
|
||||
#ifdef ASSERT
|
||||
if (TracePostallocExpand && Verbose) {
|
||||
tty->print(" removing:\n");
|
||||
for (int k = 0; k < remove.length(); ++k) {
|
||||
tty->print(" "); remove.at(k)->dump();
|
||||
}
|
||||
tty->print(" inserting:\n");
|
||||
for (int k = 0; k < new_nodes.length(); ++k) {
|
||||
tty->print(" "); new_nodes.at(k)->dump();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (int k = 0; k < remove.length(); ++k) {
|
||||
if (b->contains(remove.at(k))) {
|
||||
b->find_remove(remove.at(k));
|
||||
} else {
|
||||
assert(remove.at(k)->is_Proj() && (remove.at(k)->in(0)->is_MachBranch()), "");
|
||||
}
|
||||
}
|
||||
// If anything has been inserted (n2 != NULL), continue after last node inserted.
|
||||
// This does not always work. Some postalloc expands don't insert any nodes, if they
|
||||
// do optimizations (e.g., max(x,x)). In this case we decrement j accordingly.
|
||||
j = n2 ? b->find_node(n2) : j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (foundNode) {
|
||||
tty->print("FINISHED %d %s\n", C->compile_id(),
|
||||
C->method() ? C->method()->name()->as_utf8() : C->stub_name());
|
||||
tty->flush();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------dump-------------------------------------------
|
||||
#ifndef PRODUCT
|
||||
void PhaseCFG::_dump_cfg( const Node *end, VectorSet &visited ) const {
|
||||
const Node *x = end->is_block_proj();
|
||||
|
@ -313,10 +313,12 @@ public:
|
||||
// Add an instruction to an existing block. It must go after the head
|
||||
// instruction and before the end instruction.
|
||||
void add_inst( Node *n ) { insert_node(n, end_idx()); }
|
||||
// Find node in block
|
||||
// Find node in block. Fails if node not in block.
|
||||
uint find_node( const Node *n ) const;
|
||||
// Find and remove n from block list
|
||||
void find_remove( const Node *n );
|
||||
// Check wether the node is in the block.
|
||||
bool contains (const Node *n) const;
|
||||
|
||||
// Return the empty status of a block
|
||||
enum { not_empty, empty_with_goto, completely_empty };
|
||||
@ -596,6 +598,9 @@ class PhaseCFG : public Phase {
|
||||
map_node_to_block(n, b);
|
||||
}
|
||||
|
||||
// Check all nodes and postalloc_expand them if necessary.
|
||||
void postalloc_expand(PhaseRegAlloc* _ra);
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool trace_opto_pipelining() const { return _trace_opto_pipelining; }
|
||||
|
||||
|
@ -463,6 +463,9 @@
|
||||
experimental(bool, AggressiveUnboxing, false, \
|
||||
"Control optimizations for aggressive boxing elimination") \
|
||||
\
|
||||
develop(bool, TracePostallocExpand, false, "Trace expanding nodes after" \
|
||||
" register allocation.") \
|
||||
\
|
||||
product(bool, DoEscapeAnalysis, true, \
|
||||
"Perform escape analysis") \
|
||||
\
|
||||
|
@ -2250,6 +2250,12 @@ void Compile::Code_Gen() {
|
||||
peep.do_transform();
|
||||
}
|
||||
|
||||
// Do late expand if CPU requires this.
|
||||
if (Matcher::require_postalloc_expand) {
|
||||
NOT_PRODUCT(TracePhase t2c("postalloc_expand", &_t_postalloc_expand, true));
|
||||
cfg.postalloc_expand(_regalloc);
|
||||
}
|
||||
|
||||
// Convert Nodes to instruction bits in a buffer
|
||||
{
|
||||
// %%%% workspace merge brought two timers together for one job
|
||||
|
@ -134,6 +134,10 @@ void MachNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
//---------------------------postalloc_expand----------------------------------
|
||||
// Expand node after register allocation.
|
||||
void MachNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {}
|
||||
|
||||
//------------------------------size-------------------------------------------
|
||||
// Size of instruction in bytes
|
||||
uint MachNode::size(PhaseRegAlloc *ra_) const {
|
||||
|
@ -155,7 +155,15 @@ public:
|
||||
virtual void ext_format(PhaseRegAlloc *,const MachNode *node,int idx, outputStream *st) const=0;
|
||||
|
||||
virtual void dump_spec(outputStream *st) const; // Print per-operand info
|
||||
#endif
|
||||
|
||||
// Check whether o is a valid oper.
|
||||
static bool notAnOper(const MachOper *o) {
|
||||
if (o == NULL) return true;
|
||||
if (((intptr_t)o & 1) != 0) return true;
|
||||
if (*(address*)o == badAddress) return true; // kill by Node::destruct
|
||||
return false;
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
};
|
||||
|
||||
//------------------------------MachNode---------------------------------------
|
||||
@ -220,6 +228,12 @@ public:
|
||||
|
||||
// Emit bytes into cbuf
|
||||
virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;
|
||||
// Expand node after register allocation.
|
||||
// Node is replaced by several nodes in the postalloc expand phase.
|
||||
// Corresponding methods are generated for nodes if they specify
|
||||
// postalloc_expand. See block.cpp for more documentation.
|
||||
virtual bool requires_postalloc_expand() const { return false; }
|
||||
virtual void postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_);
|
||||
// Size of instruction in bytes
|
||||
virtual uint size(PhaseRegAlloc *ra_) const;
|
||||
// Helper function that computes size by emitting code
|
||||
@ -356,6 +370,9 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegP; }
|
||||
virtual uint oper_input_base() const { return 1; }
|
||||
|
||||
virtual bool requires_postalloc_expand() const;
|
||||
virtual void postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_);
|
||||
|
||||
virtual void emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const;
|
||||
virtual uint size(PhaseRegAlloc* ra_) const;
|
||||
virtual bool pinned() const { return UseRDPCForConstantTableBase; }
|
||||
|
@ -449,6 +449,10 @@ public:
|
||||
// aligned.
|
||||
static const bool misaligned_doubles_ok;
|
||||
|
||||
// Does the CPU require postalloc expand (see block.cpp for description of
|
||||
// postalloc expand)?
|
||||
static const bool require_postalloc_expand;
|
||||
|
||||
// Perform a platform dependent implicit null fixup. This is needed
|
||||
// on windows95 to take care of some unusual register constraints.
|
||||
void pd_implicit_null_fixup(MachNode *load, uint idx);
|
||||
|
@ -357,6 +357,8 @@ protected:
|
||||
|
||||
// Reference to the i'th input Node. Error if out of bounds.
|
||||
Node* in(uint i) const { assert(i < _max, err_msg_res("oob: i=%d, _max=%d", i, _max)); return _in[i]; }
|
||||
// Reference to the i'th input Node. NULL if out of bounds.
|
||||
Node* lookup(uint i) const { return ((i < _max) ? _in[i] : NULL); }
|
||||
// Reference to the i'th output Node. Error if out of bounds.
|
||||
// Use this accessor sparingly. We are going trying to use iterators instead.
|
||||
Node* raw_out(uint i) const { assert(i < _outcnt,"oob"); return _out[i]; }
|
||||
@ -384,6 +386,10 @@ protected:
|
||||
|
||||
// Set a required input edge, also updates corresponding output edge
|
||||
void add_req( Node *n ); // Append a NEW required input
|
||||
void add_req( Node *n0, Node *n1 ) {
|
||||
add_req(n0); add_req(n1); }
|
||||
void add_req( Node *n0, Node *n1, Node *n2 ) {
|
||||
add_req(n0); add_req(n1); add_req(n2); }
|
||||
void add_req_batch( Node* n, uint m ); // Append m NEW required inputs (all n).
|
||||
void del_req( uint idx ); // Delete required edge & compact
|
||||
void del_req_ordered( uint idx ); // Delete required edge & compact with preserved order
|
||||
@ -1350,7 +1356,7 @@ class Node_List : public Node_Array {
|
||||
public:
|
||||
Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {}
|
||||
Node_List(Arena *a) : Node_Array(a), _cnt(0) {}
|
||||
bool contains(Node* n) {
|
||||
bool contains(const Node* n) const {
|
||||
for (uint e = 0; e < size(); e++) {
|
||||
if (at(e) == n) return true;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "code/nmethod.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "opto/compile.hpp"
|
||||
#include "opto/matcher.hpp"
|
||||
#include "opto/node.hpp"
|
||||
#include "opto/phase.hpp"
|
||||
|
||||
@ -55,6 +56,7 @@ elapsedTimer Phase::_t_blockOrdering;
|
||||
elapsedTimer Phase::_t_macroEliminate;
|
||||
elapsedTimer Phase::_t_macroExpand;
|
||||
elapsedTimer Phase::_t_peephole;
|
||||
elapsedTimer Phase::_t_postalloc_expand;
|
||||
elapsedTimer Phase::_t_codeGeneration;
|
||||
elapsedTimer Phase::_t_registerMethod;
|
||||
elapsedTimer Phase::_t_temporaryTimer1;
|
||||
@ -144,6 +146,9 @@ void Phase::print_timers() {
|
||||
}
|
||||
tty->print_cr (" blockOrdering : %3.3f sec", Phase::_t_blockOrdering.seconds());
|
||||
tty->print_cr (" peephole : %3.3f sec", Phase::_t_peephole.seconds());
|
||||
if (Matcher::require_postalloc_expand) {
|
||||
tty->print_cr (" postalloc_expand: %3.3f sec", Phase::_t_postalloc_expand.seconds());
|
||||
}
|
||||
tty->print_cr (" codeGen : %3.3f sec", Phase::_t_codeGeneration.seconds());
|
||||
tty->print_cr (" install_code : %3.3f sec", Phase::_t_registerMethod.seconds());
|
||||
tty->print_cr (" -------------- : ----------");
|
||||
|
@ -91,6 +91,7 @@ protected:
|
||||
static elapsedTimer _t_macroEliminate;
|
||||
static elapsedTimer _t_macroExpand;
|
||||
static elapsedTimer _t_peephole;
|
||||
static elapsedTimer _t_postalloc_expand;
|
||||
static elapsedTimer _t_codeGeneration;
|
||||
static elapsedTimer _t_registerMethod;
|
||||
static elapsedTimer _t_temporaryTimer1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user