diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp
index 8c1e0351649c9d1f964ca01198706b4e2c329f48..779e5b3cbe72941237a1bcc95cf70764e8deac74 100644
--- a/src/hotspot/share/opto/superword.cpp
+++ b/src/hotspot/share/opto/superword.cpp
@@ -4228,11 +4228,42 @@ bool SWPointer::scaled_iv_plus_offset(Node* n) {
     }
   } else if (opc == Op_SubI) {
     if (offset_plus_k(n->in(2), true) && scaled_iv_plus_offset(n->in(1))) {
+      // (offset1 + invar1 + scale * iv) - (offset2) or
+      // (offset1 + scale * iv) - (offset2 + invar1)
+      // Subtraction handled via "negate" flag of "offset_plus_k".
       NOT_PRODUCT(_tracer.scaled_iv_plus_offset_6(n);)
       return true;
     }
-    if (offset_plus_k(n->in(1)) && scaled_iv_plus_offset(n->in(2))) {
-      _scale *= -1;
+    SWPointer tmp(this);
+    if (offset_plus_k(n->in(1)) && tmp.scaled_iv_plus_offset(n->in(2))) {
+      // (offset1 + invar1) - (offset2 + scale * iv) or
+      // (offset1) - (offset2 + invar1 + scale * iv)
+      // Subtraction handled explicitly below.
+      assert(_scale == 0, "shouldn't be set yet");
+      // _scale = -tmp._scale
+      if (!try_MulI_no_overflow(-1, tmp._scale, _scale)) {
+        return false; // mul overflow.
+      }
+      // _offset -= tmp._offset
+      if (!try_SubI_no_overflow(_offset, tmp._offset, _offset)) {
+        return false; // sub overflow.
+      }
+      // _invar -= tmp._invar
+      if (tmp._invar != nullptr) {
+        if (_invar != nullptr) {
+          return false;
+        }
+        _invar = tmp._invar;
+        _invar_scale = tmp._invar_scale;
+        _negate_invar = !tmp._negate_invar;
+      }
+
+      // SWPointer tmp does not have an integer part to be forwarded
+      // (tmp._has_int_index_after_convI2L is false) because n is a SubI, all
+      // nodes above must also be of integer type (ConvL2I is not handled
+      // to allow a long) and ConvI2L (the only node that can add an integer
+      // part) won't be present.
+
       NOT_PRODUCT(_tracer.scaled_iv_plus_offset_7(n);)
       return true;
     }
@@ -4275,7 +4306,9 @@ bool SWPointer::scaled_iv(Node* n) {
     }
   } else if (opc == Op_LShiftI) {
     if (n->in(1) == iv() && n->in(2)->is_Con()) {
-      _scale = 1 << n->in(2)->get_int();
+      if (!try_LShiftI_no_overflow(1, n->in(2)->get_int(), _scale)) {
+        return false; // shift overflow.
+      }
       NOT_PRODUCT(_tracer.scaled_iv_6(n, _scale);)
       return true;
     }
@@ -4298,15 +4331,29 @@ bool SWPointer::scaled_iv(Node* n) {
     if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) {
       // We successfully matched an integer index, of the form:
       //   int_index = int_offset + int_invar + int_scale * iv
+      // Forward scale.
+      assert(_scale == 0 && tmp._scale != 0, "iv only found just now");
+      _scale = tmp._scale;
+      // Accumulate offset.
+      if (!try_AddI_no_overflow(_offset, tmp._offset, _offset)) {
+        return false; // add overflow.
+      }
+      // Forward invariant if not already found.
+      if (tmp._invar != nullptr) {
+        if (_invar != nullptr) {
+          return false;
+        }
+        _invar = tmp._invar;
+        _invar_scale = tmp._invar_scale;
+        _negate_invar = tmp._negate_invar;
+      }
+      // Set info about the int_index:
+      assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
       _has_int_index_after_convI2L = true;
       _int_index_after_convI2L_offset = tmp._offset;
       _int_index_after_convI2L_invar  = tmp._invar;
       _int_index_after_convI2L_scale  = tmp._scale;
-    }
 
-    // Now parse it again for the real SWPointer. This makes sure that the int_offset, int_invar,
-    // and int_scale are properly added to the final SWPointer's offset, invar, and scale.
-    if (scaled_iv_plus_offset(n->in(1))) {
       NOT_PRODUCT(_tracer.scaled_iv_7(n);)
       return true;
     }
@@ -4325,12 +4372,14 @@ bool SWPointer::scaled_iv(Node* n) {
       NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);)
 
       if (tmp.scaled_iv_plus_offset(n->in(1))) {
-        int scale = n->in(2)->get_int();
+        int shift = n->in(2)->get_int();
         // Accumulate scale.
-        _scale   = tmp._scale  << scale;
+        if (!try_LShiftI_no_overflow(tmp._scale, shift, _scale)) {
+          return false; // shift overflow.
+        }
         // Accumulate offset.
         int shifted_offset = 0;
-        if (!try_LShiftI_no_overflow(tmp._offset, scale, shifted_offset)) {
+        if (!try_LShiftI_no_overflow(tmp._offset, shift, shifted_offset)) {
           return false; // shift overflow.
         }
         if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) {
@@ -4344,6 +4393,7 @@ bool SWPointer::scaled_iv(Node* n) {
         }
 
         // Forward info about the int_index:
+        assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
         _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L;
         _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset;
         _int_index_after_convI2L_invar  = tmp._int_index_after_convI2L_invar;
@@ -4486,6 +4536,9 @@ bool SWPointer::try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, i
 }
 
 bool SWPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) {
+  if (shift < 0 || shift > 31) {
+    return false;
+  }
   jlong long_offset = java_shift_left((jlong)(offset), (julong)((jlong)(shift)));
   jint  int_offset  = java_shift_left((jint)(offset), (juint)((jint)(shift)));
   if (long_offset != int_offset) {
@@ -4495,6 +4548,16 @@ bool SWPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) {
   return true;
 }
 
+bool SWPointer::try_MulI_no_overflow(int offset1, int offset2, int& result) {
+  jlong long_offset = java_multiply((jlong)(offset1), (jlong)(offset2));
+  jint  int_offset  = java_multiply((jint)(offset1), (jint)(offset2));
+  if (long_offset != int_offset) {
+    return false;
+  }
+  result = int_offset;
+  return true;
+}
+
 //----------------------------print------------------------
 void SWPointer::print() {
 #ifndef PRODUCT
diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp
index bb7f8b72997713a3036dd3b5d8e5b757fd3e5bb7..5d95a14cd065695692dd2c439d41b6ea20807d15 100644
--- a/src/hotspot/share/opto/superword.hpp
+++ b/src/hotspot/share/opto/superword.hpp
@@ -814,6 +814,7 @@ class SWPointer {
   static bool try_SubI_no_overflow(int offset1, int offset2, int& result);
   static bool try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result);
   static bool try_LShiftI_no_overflow(int offset1, int offset2, int& result);
+  static bool try_MulI_no_overflow(int offset1, int offset2, int& result);
 
 };