8027626: assert(Opcode() != Op_If || outcnt() == 2) failed: bad if #1
authorroland
Thu, 08 Jan 2015 11:00:38 +0100
changeset 28486 b0df113b962e
parent 28396 7fe4347e6792
child 28488 fe78d104b5c3
8027626: assert(Opcode() != Op_If || outcnt() == 2) failed: bad if #1 Summary: IGVN encounters IfNode with single projection when optimizing dying subgraph Reviewed-by: kvn
hotspot/src/share/vm/opto/cfgnode.hpp
hotspot/src/share/vm/opto/ifnode.cpp
hotspot/src/share/vm/opto/node.cpp
--- a/hotspot/src/share/vm/opto/cfgnode.hpp	Tue Dec 16 13:49:36 2014 +0100
+++ b/hotspot/src/share/vm/opto/cfgnode.hpp	Thu Jan 08 11:00:38 2015 +0100
@@ -361,22 +361,36 @@
 #endif
 };
 
-class IfTrueNode : public CProjNode {
+class IfProjNode : public CProjNode {
 public:
-  IfTrueNode( IfNode *ifnode ) : CProjNode(ifnode,1) {
+  IfProjNode(IfNode *ifnode, uint idx) : CProjNode(ifnode,idx) {}
+  virtual Node *Identity(PhaseTransform *phase);
+
+protected:
+  // Type of If input when this branch is always taken
+  virtual bool always_taken(const TypeTuple* t) const = 0;
+};
+
+class IfTrueNode : public IfProjNode {
+public:
+  IfTrueNode( IfNode *ifnode ) : IfProjNode(ifnode,1) {
     init_class_id(Class_IfTrue);
   }
   virtual int Opcode() const;
-  virtual Node *Identity( PhaseTransform *phase );
+
+protected:
+  virtual bool always_taken(const TypeTuple* t) const { return t == TypeTuple::IFTRUE; }
 };
 
-class IfFalseNode : public CProjNode {
+class IfFalseNode : public IfProjNode {
 public:
-  IfFalseNode( IfNode *ifnode ) : CProjNode(ifnode,0) {
+  IfFalseNode( IfNode *ifnode ) : IfProjNode(ifnode,0) {
     init_class_id(Class_IfFalse);
   }
   virtual int Opcode() const;
-  virtual Node *Identity( PhaseTransform *phase );
+
+protected:
+  virtual bool always_taken(const TypeTuple* t) const { return t == TypeTuple::IFFALSE; }
 };
 
 
--- a/hotspot/src/share/vm/opto/ifnode.cpp	Tue Dec 16 13:49:36 2014 +0100
+++ b/hotspot/src/share/vm/opto/ifnode.cpp	Thu Jan 08 11:00:38 2015 +0100
@@ -1122,12 +1122,21 @@
 
 //------------------------------Identity---------------------------------------
 // If the test is constant & we match, then we are the input Control
-Node *IfTrueNode::Identity( PhaseTransform *phase ) {
+Node *IfProjNode::Identity(PhaseTransform *phase) {
   // Can only optimize if cannot go the other way
   const TypeTuple *t = phase->type(in(0))->is_tuple();
-  return ( t == TypeTuple::IFNEITHER || t == TypeTuple::IFTRUE )
-    ? in(0)->in(0)              // IfNode control
-    : this;                     // no progress
+  if (t == TypeTuple::IFNEITHER ||
+      // kill dead branch first otherwise the IfNode's control will
+      // have 2 control uses (the IfNode that doesn't go away because
+      // it still has uses and this branch of the
+      // If). Node::has_special_unique_user() will cause this node to
+      // be reprocessed once the dead branch is killed.
+      (always_taken(t) && in(0)->outcnt() == 1)) {
+    // IfNode control
+    return in(0)->in(0);
+  }
+  // no progress
+  return this;
 }
 
 //------------------------------dump_spec--------------------------------------
@@ -1195,13 +1204,3 @@
   // Progress
   return iff;
 }
-
-//------------------------------Identity---------------------------------------
-// If the test is constant & we match, then we are the input Control
-Node *IfFalseNode::Identity( PhaseTransform *phase ) {
-  // Can only optimize if cannot go the other way
-  const TypeTuple *t = phase->type(in(0))->is_tuple();
-  return ( t == TypeTuple::IFNEITHER || t == TypeTuple::IFFALSE )
-    ? in(0)->in(0)              // IfNode control
-    : this;                     // no progress
-}
--- a/hotspot/src/share/vm/opto/node.cpp	Tue Dec 16 13:49:36 2014 +0100
+++ b/hotspot/src/share/vm/opto/node.cpp	Thu Jan 08 11:00:38 2015 +0100
@@ -1080,18 +1080,21 @@
   assert(outcnt() == 1, "match only for unique out");
   Node* n = unique_out();
   int op  = Opcode();
-  if( this->is_Store() ) {
+  if (this->is_Store()) {
     // Condition for back-to-back stores folding.
     return n->Opcode() == op && n->in(MemNode::Memory) == this;
   } else if (this->is_Load()) {
     // Condition for removing an unused LoadNode from the MemBarAcquire precedence input
     return n->Opcode() == Op_MemBarAcquire;
-  } else if( op == Op_AddL ) {
+  } else if (op == Op_AddL) {
     // Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
     return n->Opcode() == Op_ConvL2I && n->in(1) == this;
-  } else if( op == Op_SubI || op == Op_SubL ) {
+  } else if (op == Op_SubI || op == Op_SubL) {
     // Condition for subI(x,subI(y,z)) ==> subI(addI(x,z),y)
     return n->Opcode() == op && n->in(2) == this;
+  } else if (is_If() && (n->is_IfFalse() || n->is_IfTrue())) {
+    // See IfProjNode::Identity()
+    return true;
   }
   return false;
 };