This commit is contained in:
Vladimir Kozlov 2013-11-15 14:09:26 -05:00
commit fa597af116
20 changed files with 689 additions and 92 deletions

@ -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;