changeset 2616:11211f7cb5a0

7079317: Incorrect branch's destination block in PrintoOptoAssembly output Summary: save/restore label and block in scratch_emit_size() Reviewed-by: never
author kvn
date Tue, 16 Aug 2011 11:53:57 -0700
parents fdb992d83a87
children 1af104d6cf99
files src/share/vm/adlc/archDesc.cpp src/share/vm/adlc/formssel.cpp src/share/vm/adlc/output_c.cpp src/share/vm/adlc/output_h.cpp src/share/vm/opto/block.cpp src/share/vm/opto/compile.cpp src/share/vm/opto/idealGraphPrinter.cpp src/share/vm/opto/machnode.cpp src/share/vm/opto/machnode.hpp src/share/vm/opto/node.hpp src/share/vm/opto/output.cpp
diffstat 11 files changed, 84 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/adlc/archDesc.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/adlc/archDesc.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -331,6 +331,11 @@
     // Find result type for match
     const char *result  = instr->reduce_result();
 
+    if ( instr->is_ideal_branch() && instr->label_position() == -1 ||
+        !instr->is_ideal_branch() && instr->label_position() != -1) {
+      syntax_err(instr->_linenum, "%s: Only branches to a label are supported\n", rootOp);
+    }
+
     Attribute *attr = instr->_attribs;
     while (attr != NULL) {
       if (strcmp(attr->_ident,"ins_short_branch") == 0 &&
--- a/src/share/vm/adlc/formssel.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/adlc/formssel.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -340,12 +340,11 @@
   return _matrule->is_ideal_jump();
 }
 
-// Return 'true' if instruction matches ideal 'If' | 'Goto' |
-//                    'CountedLoopEnd' | 'Jump'
+// Return 'true' if instruction matches ideal 'If' | 'Goto' | 'CountedLoopEnd'
 bool InstructForm::is_ideal_branch() const {
   if( _matrule == NULL ) return false;
 
-  return _matrule->is_ideal_if() || _matrule->is_ideal_goto() || _matrule->is_ideal_jump();
+  return _matrule->is_ideal_if() || _matrule->is_ideal_goto();
 }
 
 
@@ -383,7 +382,7 @@
 bool InstructForm::is_ideal_control() const {
   if ( ! _matrule)  return false;
 
-  return is_ideal_return() || is_ideal_branch() || is_ideal_halt();
+  return is_ideal_return() || is_ideal_branch() || _matrule->is_ideal_jump() || is_ideal_halt();
 }
 
 // Return 'true' if this instruction matches an ideal 'Call' node
--- a/src/share/vm/adlc/output_c.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/adlc/output_c.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -3094,6 +3094,13 @@
       fprintf(fp,"  oper->_label     = label;\n");
       fprintf(fp,"  oper->_block_num = block_num;\n");
       fprintf(fp,"}\n");
+      // Save the label
+      fprintf(fp,"void %sNode::save_label( Label** label, uint* block_num ) {\n", instr->_ident);
+      fprintf(fp,"  labelOper* oper  = (labelOper*)(opnd_array(%d));\n",
+              label_position );
+      fprintf(fp,"  *label = oper->_label;\n");
+      fprintf(fp,"  *block_num = oper->_block_num;\n");
+      fprintf(fp,"}\n");
     }
   }
 
--- a/src/share/vm/adlc/output_h.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/adlc/output_h.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -1519,8 +1519,9 @@
     // Declare Node::methods that set operand Label's contents
     int label_position = instr->label_position();
     if( label_position != -1 ) {
-      // Set the label, stored in labelOper::_branch_label
+      // Set/Save the label, stored in labelOper::_branch_label
       fprintf(fp,"  virtual void           label_set( Label* label, uint block_num );\n");
+      fprintf(fp,"  virtual void           save_label( Label** label, uint* block_num );\n");
     }
 
     // If this instruction contains a methodOper
@@ -1678,16 +1679,6 @@
       }
     }
 
-    // flag: if instruction matches 'If' | 'Goto' | 'CountedLoopEnd | 'Jump'
-    if ( instr->is_ideal_branch() ) {
-      if ( node_flags_set ) {
-        fprintf(fp," | Flag_is_Branch");
-      } else {
-        fprintf(fp,"init_flags(Flag_is_Branch");
-        node_flags_set = true;
-      }
-    }
-
     // flag: if this instruction is cisc alternate
     if ( can_cisc_spill() && instr->is_cisc_alternate() ) {
       if ( node_flags_set ) {
--- a/src/share/vm/opto/block.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/block.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -839,7 +839,7 @@
 
       // Make sure we TRUE branch to the target
       if( proj0->Opcode() == Op_IfFalse ) {
-        iff->negate();
+        iff->as_MachIf()->negate();
       }
 
       b->_nodes.pop();          // Remove IfFalse & IfTrue projections
--- a/src/share/vm/opto/compile.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/compile.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -519,15 +519,18 @@
   // Do the emission.
 
   Label fakeL; // Fake label for branch instructions.
-  bool is_branch = n->is_Branch() && n->as_Mach()->ideal_Opcode() != Op_Jump;
+  Label*   saveL = NULL;
+  uint save_bnum = 0;
+  bool is_branch = n->is_MachBranch();
   if (is_branch) {
     MacroAssembler masm(&buf);
     masm.bind(fakeL);
-    n->as_Mach()->label_set(&fakeL, 0);
+    n->as_MachBranch()->save_label(&saveL, &save_bnum);
+    n->as_MachBranch()->label_set(&fakeL, 0);
   }
   n->emit(buf, this->regalloc());
-  if (is_branch) // Clear the reference to fake label.
-    n->as_Mach()->label_set(NULL, 0);
+  if (is_branch) // Restore label.
+    n->as_MachBranch()->label_set(saveL, save_bnum);
 
   // End scratch_emit_size section.
   set_in_scratch_emit_size(false);
--- a/src/share/vm/opto/idealGraphPrinter.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/idealGraphPrinter.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -441,9 +441,6 @@
     if (flags & Node::Flag_is_cisc_alternate) {
       print_prop("is_cisc_alternate", "true");
     }
-    if (flags & Node::Flag_is_Branch) {
-      print_prop("is_branch", "true");
-    }
     if (flags & Node::Flag_is_dead_loop_safe) {
       print_prop("is_dead_loop_safe", "true");
     }
--- a/src/share/vm/opto/machnode.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/machnode.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -389,12 +389,6 @@
 }
 
 
-//------------------------------negate-----------------------------------------
-// Negate conditional branches.  Error for non-branch Nodes
-void MachNode::negate() {
-  ShouldNotCallThis();
-}
-
 //------------------------------peephole---------------------------------------
 // Apply peephole rule(s) to this instruction
 MachNode *MachNode::peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ) {
@@ -407,12 +401,6 @@
   ShouldNotCallThis();
 }
 
-//------------------------------label_set--------------------------------------
-// Set the Label for a LabelOper, if an operand for this instruction
-void MachNode::label_set( Label* label, uint block_num ) {
-  ShouldNotCallThis();
-}
-
 //------------------------------method_set-------------------------------------
 // Set the absolute address of a method
 void MachNode::method_set( intptr_t addr ) {
@@ -517,6 +505,9 @@
 void MachNullCheckNode::label_set(Label* label, uint block_num) {
   // Nothing to emit
 }
+void MachNullCheckNode::save_label( Label** label, uint* block_num ) {
+  // Nothing to emit
+}
 
 const RegMask &MachNullCheckNode::in_RegMask( uint idx ) const {
   if( idx == 0 ) return RegMask::Empty;
--- a/src/share/vm/opto/machnode.hpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/machnode.hpp	Tue Aug 16 11:53:57 2011 -0700
@@ -185,7 +185,6 @@
   virtual void use_cisc_RegMask();
 
   // Support for short branches
-  virtual MachNode *short_branch_version(Compile* C) { return NULL; }
   bool may_be_short_branch() const { return (flags() & Flag_may_be_short_branch) != 0; }
 
   // Avoid back to back some instructions on some CPUs.
@@ -272,18 +271,12 @@
   // Call "get_base_and_disp" to decide which category of memory is used here.
   virtual const class TypePtr *adr_type() const;
 
-  // Negate conditional branches.  Error for non-branch Nodes
-  virtual void negate();
-
   // Apply peephole rule(s) to this instruction
   virtual MachNode *peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C );
 
   // Top-level ideal Opcode matched
   virtual int ideal_Opcode()     const { return Op_Node; }
 
-  // Set the branch inside jump MachNodes.  Error for non-branch Nodes.
-  virtual void label_set( Label* label, uint block_num );
-
   // Adds the label for the case
   virtual void add_case_label( int switch_val, Label* blockLabel);
 
@@ -514,25 +507,41 @@
 #endif
 };
 
+//------------------------------MachBranchNode--------------------------------
+// Abstract machine branch Node
+class MachBranchNode : public MachIdealNode {
+public:
+  MachBranchNode() : MachIdealNode() {
+    init_class_id(Class_MachBranch);
+  }
+  virtual void label_set(Label* label, uint block_num) = 0;
+  virtual void save_label(Label** label, uint* block_num) = 0;
+
+  // Support for short branches
+  virtual MachNode *short_branch_version(Compile* C) { return NULL; }
+
+  virtual bool pinned() const { return true; };
+};
+
 //------------------------------MachNullChkNode--------------------------------
 // Machine-dependent null-pointer-check Node.  Points a real MachNode that is
 // also some kind of memory op.  Turns the indicated MachNode into a
 // conditional branch with good latency on the ptr-not-null path and awful
 // latency on the pointer-is-null path.
 
-class MachNullCheckNode : public MachIdealNode {
+class MachNullCheckNode : public MachBranchNode {
 public:
   const uint _vidx;             // Index of memop being tested
-  MachNullCheckNode( Node *ctrl, Node *memop, uint vidx ) : MachIdealNode(), _vidx(vidx) {
+  MachNullCheckNode( Node *ctrl, Node *memop, uint vidx ) : MachBranchNode(), _vidx(vidx) {
     init_class_id(Class_MachNullCheck);
-    init_flags(Flag_is_Branch);
     add_req(ctrl);
     add_req(memop);
   }
+  virtual uint size_of() const { return sizeof(*this); }
 
   virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;
   virtual void label_set(Label* label, uint block_num);
-  virtual bool pinned() const { return true; };
+  virtual void save_label(Label** label, uint* block_num);
   virtual void negate() { }
   virtual const class Type *bottom_type() const { return TypeTuple::IFBOTH; }
   virtual uint ideal_reg() const { return NotAMachineReg; }
@@ -578,14 +587,16 @@
 
 //------------------------------MachIfNode-------------------------------------
 // Machine-specific versions of IfNodes
-class MachIfNode : public MachNode {
+class MachIfNode : public MachBranchNode {
   virtual uint size_of() const { return sizeof(*this); } // Size is bigger
 public:
   float _prob;                  // Probability branch goes either way
   float _fcnt;                  // Frequency counter
-  MachIfNode() : MachNode() {
+  MachIfNode() : MachBranchNode() {
     init_class_id(Class_MachIf);
   }
+  // Negate conditional branches.
+  virtual void negate() = 0;
 #ifndef PRODUCT
   virtual void dump_spec(outputStream *st) const;
 #endif
@@ -593,9 +604,9 @@
 
 //------------------------------MachGotoNode-----------------------------------
 // Machine-specific versions of GotoNodes
-class MachGotoNode : public MachNode {
+class MachGotoNode : public MachBranchNode {
 public:
-  MachGotoNode() : MachNode() {
+  MachGotoNode() : MachBranchNode() {
     init_class_id(Class_MachGoto);
   }
 };
--- a/src/share/vm/opto/node.hpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/node.hpp	Tue Aug 16 11:53:57 2011 -0700
@@ -77,6 +77,7 @@
 class LoadStoreNode;
 class LockNode;
 class LoopNode;
+class MachBranchNode;
 class MachCallDynamicJavaNode;
 class MachCallJavaNode;
 class MachCallLeafNode;
@@ -572,13 +573,14 @@
               DEFINE_CLASS_ID(MachCallDynamicJava,  MachCallJava, 1)
             DEFINE_CLASS_ID(MachCallRuntime,      MachCall, 1)
               DEFINE_CLASS_ID(MachCallLeaf,         MachCallRuntime, 0)
-      DEFINE_CLASS_ID(MachSpillCopy,    Mach, 1)
-      DEFINE_CLASS_ID(MachNullCheck,    Mach, 2)
-      DEFINE_CLASS_ID(MachIf,           Mach, 3)
-      DEFINE_CLASS_ID(MachTemp,         Mach, 4)
-      DEFINE_CLASS_ID(MachConstantBase, Mach, 5)
-      DEFINE_CLASS_ID(MachConstant,     Mach, 6)
-      DEFINE_CLASS_ID(MachGoto,         Mach, 7)
+      DEFINE_CLASS_ID(MachBranch, Mach, 1)
+        DEFINE_CLASS_ID(MachIf,         MachBranch, 0)
+        DEFINE_CLASS_ID(MachGoto,       MachBranch, 1)
+        DEFINE_CLASS_ID(MachNullCheck,  MachBranch, 2)
+      DEFINE_CLASS_ID(MachSpillCopy,    Mach, 2)
+      DEFINE_CLASS_ID(MachTemp,         Mach, 3)
+      DEFINE_CLASS_ID(MachConstantBase, Mach, 4)
+      DEFINE_CLASS_ID(MachConstant,     Mach, 5)
 
     DEFINE_CLASS_ID(Type,  Node, 2)
       DEFINE_CLASS_ID(Phi,   Type, 0)
@@ -634,8 +636,7 @@
     Flag_is_macro            = Flag_needs_anti_dependence_check << 1,
     Flag_is_Con              = Flag_is_macro << 1,
     Flag_is_cisc_alternate   = Flag_is_Con << 1,
-    Flag_is_Branch           = Flag_is_cisc_alternate << 1,
-    Flag_is_dead_loop_safe   = Flag_is_Branch << 1,
+    Flag_is_dead_loop_safe   = Flag_is_cisc_alternate << 1,
     Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1,
     Flag_avoid_back_to_back  = Flag_may_be_short_branch << 1,
     _max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination
@@ -721,6 +722,7 @@
   DEFINE_CLASS_QUERY(Lock)
   DEFINE_CLASS_QUERY(Loop)
   DEFINE_CLASS_QUERY(Mach)
+  DEFINE_CLASS_QUERY(MachBranch)
   DEFINE_CLASS_QUERY(MachCall)
   DEFINE_CLASS_QUERY(MachCallDynamicJava)
   DEFINE_CLASS_QUERY(MachCallJava)
@@ -787,9 +789,6 @@
   // skip some other important test.)
   virtual bool depends_only_on_test() const { assert(!is_CFG(), ""); return true; };
 
-  // defined for MachNodes that match 'If' | 'Goto' | 'CountedLoopEnd' | 'Jump'
-  bool is_Branch() const { return (_flags & Flag_is_Branch) != 0; }
-
   // When building basic blocks, I need to have a notion of block beginning
   // Nodes, next block selector Nodes (block enders), and next block
   // projections.  These calls need to work on their machine equivalents.  The
--- a/src/share/vm/opto/output.cpp	Tue Aug 16 04:14:05 2011 -0700
+++ b/src/share/vm/opto/output.cpp	Tue Aug 16 11:53:57 2011 -0700
@@ -420,7 +420,7 @@
           }
         }
         if (mach->may_be_short_branch()) {
-          if (!nj->is_Branch()) {
+          if (!nj->is_MachBranch()) {
 #ifndef PRODUCT
             nj->dump(3);
 #endif
@@ -473,7 +473,7 @@
       MachNode* mach = (idx == -1) ? NULL: b->_nodes[idx]->as_Mach();
       if (mach != NULL && mach->may_be_short_branch()) {
 #ifdef ASSERT
-        assert(jmp_size[i] > 0 && mach->is_Branch(), "sanity");
+        assert(jmp_size[i] > 0 && mach->is_MachBranch(), "sanity");
         int j;
         // Find the branch; ignore trailing NOPs.
         for (j = b->_nodes.size()-1; j>=0; j--) {
@@ -500,7 +500,7 @@
 
         if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
           // We've got a winner.  Replace this branch.
-          MachNode* replacement = mach->short_branch_version(this);
+          MachNode* replacement = mach->as_MachBranch()->short_branch_version(this);
 
           // Update the jmp_size.
           int new_size = replacement->size(_regalloc);
@@ -670,7 +670,7 @@
 
           if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
             // We've got a winner.  Replace this branch.
-            MachNode* replacement = mach->short_branch_version(this);
+            MachNode* replacement = mach->as_MachBranch()->short_branch_version(this);
 
             // Update the jmp_size.
             int new_size = replacement->size(_regalloc);
@@ -1525,25 +1525,21 @@
         }
 
         // If this is a branch, then fill in the label with the target BB's label
-        else if (mach->is_Branch()) {
-
-          if (mach->ideal_Opcode() == Op_Jump) {
-            for (uint h = 0; h < b->_num_succs; h++) {
-              Block* succs_block = b->_succs[h];
-              for (uint j = 1; j < succs_block->num_preds(); j++) {
-                Node* jpn = succs_block->pred(j);
-                if (jpn->is_JumpProj() && jpn->in(0) == mach) {
-                  uint block_num = succs_block->non_connector()->_pre_order;
-                  Label *blkLabel = &blk_labels[block_num];
-                  mach->add_case_label(jpn->as_JumpProj()->proj_no(), blkLabel);
-                }
+        else if (mach->is_MachBranch()) {
+          // This requires the TRUE branch target be in succs[0]
+          uint block_num = b->non_connector_successor(0)->_pre_order;
+          mach->as_MachBranch()->label_set( &blk_labels[block_num], block_num );
+        } else if (mach->ideal_Opcode() == Op_Jump) {
+          for (uint h = 0; h < b->_num_succs; h++) {
+            Block* succs_block = b->_succs[h];
+            for (uint j = 1; j < succs_block->num_preds(); j++) {
+              Node* jpn = succs_block->pred(j);
+              if (jpn->is_JumpProj() && jpn->in(0) == mach) {
+                uint block_num = succs_block->non_connector()->_pre_order;
+                Label *blkLabel = &blk_labels[block_num];
+                mach->add_case_label(jpn->as_JumpProj()->proj_no(), blkLabel);
               }
             }
-          } else {
-            // For Branchs
-            // This requires the TRUE branch target be in succs[0]
-            uint block_num = b->non_connector_successor(0)->_pre_order;
-            mach->label_set( &blk_labels[block_num], block_num );
           }
         }
 
@@ -2229,7 +2225,7 @@
     // the first instruction at the branch target is
     // copied to the delay slot, and the branch goes to
     // the instruction after that at the branch target
-    if ( n->is_Mach() && n->is_Branch() ) {
+    if ( n->is_MachBranch() ) {
 
       assert( !n->is_MachNullCheck(), "should not look for delay slot for Null Check" );
       assert( !n->is_Catch(),         "should not look for delay slot for Catch" );
@@ -2890,7 +2886,7 @@
     // Kill projections on a branch should appear to occur on the
     // branch, not afterwards, so grab the masks from the projections
     // and process them.
-    if (n->is_Branch()) {
+    if (n->is_MachBranch() || n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_Jump) {
       for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
         Node* use = n->fast_out(i);
         if (use->is_Proj()) {