Merge
authorkvn
Fri, 15 Nov 2013 14:09:26 -0500
changeset 22846 5437b706504e
parent 22845 d8812d0ff387 (current diff)
parent 22844 90f76a40ed8a (diff)
child 22847 603ad1f10e16
Merge
--- 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;