< prev index next >

src/hotspot/share/opto/subnode.cpp

Print this page
@@ -28,10 +28,11 @@
  #include "gc/shared/c2/barrierSetC2.hpp"
  #include "memory/allocation.inline.hpp"
  #include "opto/addnode.hpp"
  #include "opto/callnode.hpp"
  #include "opto/cfgnode.hpp"
+ #include "opto/inlinetypenode.hpp"
  #include "opto/loopnode.hpp"
  #include "opto/matcher.hpp"
  #include "opto/movenode.hpp"
  #include "opto/mulnode.hpp"
  #include "opto/opcodes.hpp"

@@ -836,21 +837,53 @@
      }
    }
    return NULL;                  // No change
  }
  
- Node *CmpLNode::Ideal( PhaseGVN *phase, bool can_reshape ) {
+ //------------------------------Ideal------------------------------------------
+ Node* CmpLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
+   Node* a = NULL;
+   Node* b = NULL;
+   if (is_double_null_check(phase, a, b) && (phase->type(a)->is_zero_type() || phase->type(b)->is_zero_type())) {
+     // Degraded to a simple null check, use old acmp
+     return new CmpPNode(a, b);
+   }
    const TypeLong *t2 = phase->type(in(2))->isa_long();
    if (Opcode() == Op_CmpL && in(1)->Opcode() == Op_ConvI2L && t2 && t2->is_con()) {
      const jlong con = t2->get_con();
      if (con >= min_jint && con <= max_jint) {
        return new CmpINode(in(1)->in(1), phase->intcon((jint)con));
      }
    }
    return NULL;
  }
  
+ // Match double null check emitted by Compile::optimize_acmp()
+ bool CmpLNode::is_double_null_check(PhaseGVN* phase, Node*& a, Node*& b) const {
+   if (in(1)->Opcode() == Op_OrL &&
+       in(1)->in(1)->Opcode() == Op_CastP2X &&
+       in(1)->in(2)->Opcode() == Op_CastP2X &&
+       in(2)->bottom_type()->is_zero_type()) {
+     assert(EnableValhalla, "unexpected double null check");
+     a = in(1)->in(1)->in(1);
+     b = in(1)->in(2)->in(1);
+     return true;
+   }
+   return false;
+ }
+ 
+ //------------------------------Value------------------------------------------
+ const Type* CmpLNode::Value(PhaseGVN* phase) const {
+   Node* a = NULL;
+   Node* b = NULL;
+   if (is_double_null_check(phase, a, b) && (!phase->type(a)->maybe_null() || !phase->type(b)->maybe_null())) {
+     // One operand is never NULL, emit constant false
+     return TypeInt::CC_GT;
+   }
+   return SubNode::Value(phase);
+ }
+ 
  //=============================================================================
  // Simplify a CmpL (compare 2 longs ) node, based on local information.
  // If both inputs are constants, compare them.
  const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const {
    const TypeLong *r0 = t1->is_long(); // Handy access

@@ -1005,10 +1038,26 @@
          // If klass0's type is PRECISE, then classes are unrelated.
          unrelated_classes = xklass0;
        } else {                  // Neither subtypes the other
          unrelated_classes = true;
        }
+       if (!unrelated_classes) {
+         // Handle inline type arrays
+         if ((r0->flatten_array() && (!r1->can_be_inline_type() || (klass1->is_inlinetype() && !klass1->flatten_array()))) ||
+             (r1->flatten_array() && (!r0->can_be_inline_type() || (klass0->is_inlinetype() && !klass0->flatten_array())))) {
+           // One type is flattened in arrays but the other type is not. Must be unrelated.
+           unrelated_classes = true;
+         } else if ((r0->is_not_flat() && klass1->is_flat_array_klass()) ||
+                    (r1->is_not_flat() && klass0->is_flat_array_klass())) {
+           // One type is a non-flattened array and the other type is a flattened array. Must be unrelated.
+           unrelated_classes = true;
+         } else if ((r0->is_not_null_free() && klass1->is_array_klass() && klass1->as_array_klass()->is_elem_null_free()) ||
+                    (r1->is_not_null_free() && klass0->is_array_klass() && klass0->as_array_klass()->is_elem_null_free())) {
+           // One type is a non-null-free array and the other type is a null-free array. Must be unrelated.
+           unrelated_classes = true;
+         }
+       }
        if (unrelated_classes) {
          // The oops classes are known to be unrelated. If the joined PTRs of
          // two oops is not Null and not Bottom, then we are sure that one
          // of the two oops is non-null, and the comparison will always fail.
          TypePtr::PTR jp = r0->join_ptr(r1->_ptr);

@@ -1090,11 +1139,17 @@
  //
  // Also check for the case of comparing an unknown klass loaded from the primary
  // super-type array vs a known klass with no subtypes.  This amounts to
  // checking to see an unknown klass subtypes a known klass with no subtypes;
  // this only happens on an exact match.  We can shorten this test by 1 load.
- Node *CmpPNode::Ideal( PhaseGVN *phase, bool can_reshape ) {
+ Node* CmpPNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+   if (in(1)->is_InlineTypePtr() && phase->type(in(2))->is_zero_type()) {
+     // Null checking a scalarized but nullable inline type. Check the is_init
+     // input instead of the oop input to avoid keeping buffer allocations alive.
+     return new CmpINode(in(1)->as_InlineTypePtr()->get_is_init(), phase->intcon(0));
+   }
+ 
    // Normalize comparisons between Java mirrors into comparisons of the low-
    // level klass, where a dependent load could be shortened.
    //
    // The new pattern has a nice effect of matching the same pattern used in the
    // fast path of instanceof/checkcast/Class.isInstance(), which allows

@@ -1162,10 +1217,18 @@
  
    // Verify that we understand the situation
    if (con2 != (intptr_t) superklass->super_check_offset())
      return NULL;                // Might be element-klass loading from array klass
  
+   // Do not fold the subtype check to an array klass pointer comparison for [V? arrays.
+   // [QMyValue is a subtype of [LMyValue but the klass for [QMyValue is not equal to
+   // the klass for [LMyValue. Do not bypass the klass load from the primary supertype array.
+   if (superklass->is_obj_array_klass() && !superklass->as_array_klass()->is_elem_null_free() &&
+       superklass->as_array_klass()->element_klass()->is_inlinetype()) {
+     return NULL;
+   }
+ 
    // If 'superklass' has no subklasses and is not an interface, then we are
    // assured that the only input which will pass the type check is
    // 'superklass' itself.
    //
    // We could be more liberal here, and allow the optimization on interfaces

@@ -1305,10 +1368,49 @@
      // Testing value required the precision of a double
    }
    return NULL;                  // No change
  }
  
+ //=============================================================================
+ //------------------------------Value------------------------------------------
+ const Type* FlatArrayCheckNode::Value(PhaseGVN* phase) const {
+   bool all_not_flat = true;
+   for (uint i = Array; i < req(); ++i) {
+     Node* array = in(i);
+     if (!array->is_top()) {
+       const Type* t = phase->type(array);
+       if (t == Type::TOP) {
+         return Type::TOP;
+       } else if (t->is_aryptr()->is_flat()) {
+         // One of the input arrays is flat, check always passes
+         return TypeInt::CC_EQ;
+       } else if (!t->is_aryptr()->is_not_flat()) {
+         // One of the input arrays might be flat
+         all_not_flat = false;
+       }
+     }
+   }
+   if (all_not_flat) {
+     // None of the input arrays can be flat, check always fails
+     return TypeInt::CC_GT;
+   }
+   return TypeInt::CC;
+ }
+ 
+ //------------------------------Ideal------------------------------------------
+ Node* FlatArrayCheckNode::Ideal(PhaseGVN* phase, bool can_reshape) {
+   bool changed = false;
+   // Remove array inputs that are known to be non-flat
+   for (uint i = Array; i < req(); ++i) {
+     const TypeAryPtr* t = phase->type(in(i))->isa_aryptr();
+     if (t != NULL && t->is_not_flat()) {
+       set_req(i, phase->C->top());
+       changed = true;
+     }
+   }
+   return changed ? this : NULL;
+ }
  
  //=============================================================================
  //------------------------------cc2logical-------------------------------------
  // Convert a condition code type to a logical type
  const Type *BoolTest::cc2logical( const Type *CC ) const {
< prev index next >