--- a/hotspot/src/cpu/sparc/vm/sparc.ad Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Fri Nov 15 14:09:26 2013 -0500
@@ -1034,6 +1034,11 @@
}
}
+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 @@
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
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Fri Nov 15 14:09:26 2013 -0500
@@ -487,6 +487,11 @@
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 @@
// 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
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Fri Nov 15 14:09:26 2013 -0500
@@ -688,6 +688,11 @@
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 @@
// 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
--- a/hotspot/src/share/vm/adlc/adlparse.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/adlparse.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -219,19 +219,21 @@
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 @@
// 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 @@
}
// 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 @@
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 @@
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 @@
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.
--- a/hotspot/src/share/vm/adlc/adlparse.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/adlparse.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -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 @@
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);
--- a/hotspot/src/share/vm/adlc/archDesc.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/archDesc.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -311,6 +311,8 @@
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,
--- a/hotspot/src/share/vm/adlc/formssel.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/formssel.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -36,27 +36,28 @@
{
_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 @@
{
_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 @@
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;
--- a/hotspot/src/share/vm/adlc/formssel.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/formssel.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -88,30 +88,31 @@
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 @@
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
--- a/hotspot/src/share/vm/adlc/output_c.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/output_c.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -2488,7 +2488,113 @@
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 @@
} 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 @@
// 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 @@
// 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);
--- a/hotspot/src/share/vm/adlc/output_h.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/adlc/output_h.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -1633,7 +1633,12 @@
// 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
--- a/hotspot/src/share/vm/opto/block.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/block.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -144,6 +144,10 @@
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 @@
// 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 @@
}
+// 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();
--- a/hotspot/src/share/vm/opto/block.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/block.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -313,10 +313,12 @@
// 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 @@
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; }
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -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") \
\
--- a/hotspot/src/share/vm/opto/compile.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -2250,6 +2250,12 @@
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
--- a/hotspot/src/share/vm/opto/machnode.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/machnode.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -134,6 +134,10 @@
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 {
--- a/hotspot/src/share/vm/opto/machnode.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/machnode.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -155,7 +155,15 @@
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 @@
// 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 @@
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; }
--- a/hotspot/src/share/vm/opto/matcher.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/matcher.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -449,6 +449,10 @@
// 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);
--- a/hotspot/src/share/vm/opto/node.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/node.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -357,6 +357,8 @@
// 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 @@
// 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 @@
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;
}
--- a/hotspot/src/share/vm/opto/phase.cpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/phase.cpp Fri Nov 15 14:09:26 2013 -0500
@@ -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_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 @@
}
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 (" -------------- : ----------");
--- a/hotspot/src/share/vm/opto/phase.hpp Fri Nov 15 11:05:32 2013 -0800
+++ b/hotspot/src/share/vm/opto/phase.hpp Fri Nov 15 14:09:26 2013 -0500
@@ -91,6 +91,7 @@
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;