diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index b503810b4eff5..fac643b9d228a 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -36,6 +36,7 @@ #include "opto/mulnode.hpp" #include "opto/opcodes.hpp" #include "opto/opaquenode.hpp" +#include "opto/rootnode.hpp" #include "opto/superword.hpp" #include "opto/vectornode.hpp" #include "opto/movenode.hpp" @@ -201,7 +202,6 @@ bool SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { //------------------------------early unrolling analysis------------------------------ void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) { bool is_slp = true; - ResourceMark rm; size_t ignored_size = lpt()->_body.size(); int *ignored_loop_nodes = NEW_RESOURCE_ARRAY(int, ignored_size); Node_Stack nstack((int)ignored_size); @@ -4248,19 +4248,7 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) { invar = new ConvL2INode(invar); _igvn.register_new_node_with_optimizer(invar); } - Node* invar_scale = align_to_ref_p.invar_scale(); - if (invar_scale != nullptr) { - invar = new LShiftINode(invar, invar_scale); - _igvn.register_new_node_with_optimizer(invar); - } - Node* aref = new URShiftINode(invar, log2_elt); - _igvn.register_new_node_with_optimizer(aref); - _phase->set_ctrl(aref, pre_ctrl); - if (align_to_ref_p.negate_invar()) { - e = new SubINode(e, aref); - } else { - e = new AddINode(e, aref); - } + e = new URShiftINode(invar, log2_elt); _igvn.register_new_node_with_optimizer(e); _phase->set_ctrl(e, pre_ctrl); } @@ -4440,9 +4428,11 @@ int SWPointer::Tracer::_depth = 0; #endif //----------------------------SWPointer------------------------ SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool analyze_only) : - _mem(mem), _slp(slp), _base(nullptr), _adr(nullptr), - _scale(0), _offset(0), _invar(nullptr), _negate_invar(false), - _invar_scale(nullptr), + _mem(mem), _slp(slp), _base(nullptr), _adr(nullptr), + _scale(0), _offset(0), _invar(nullptr), +#ifdef ASSERT + _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr), +#endif _nstack(nstack), _analyze_only(analyze_only), _stack_idx(0) #ifndef PRODUCT @@ -4473,7 +4463,7 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool anal NOT_PRODUCT(_tracer.ctor_2(adr);) int i; - for (i = 0; i < 3; i++) { + for (i = 0; ; i++) { NOT_PRODUCT(_tracer.ctor_3(adr, i);) if (!scaled_iv_plus_offset(adr->in(AddPNode::Offset))) { @@ -4509,9 +4499,11 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool anal // Following is used to create a temporary object during // the pattern match of an address expression. SWPointer::SWPointer(SWPointer* p) : - _mem(p->_mem), _slp(p->_slp), _base(nullptr), _adr(nullptr), - _scale(0), _offset(0), _invar(nullptr), _negate_invar(false), - _invar_scale(nullptr), + _mem(p->_mem), _slp(p->_slp), _base(nullptr), _adr(nullptr), + _scale(0), _offset(0), _invar(nullptr), +#ifdef ASSERT + _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr), +#endif _nstack(p->_nstack), _analyze_only(p->_analyze_only), _stack_idx(p->_stack_idx) #ifndef PRODUCT @@ -4625,7 +4617,7 @@ bool SWPointer::scaled_iv(Node* n) { return true; } } else if (opc == Op_LShiftL && n->in(2)->is_Con()) { - if (!has_iv() && _invar == nullptr) { + if (!has_iv()) { // Need to preserve the current _offset value, so // create a temporary object for this expression subtree. // Hacky, so should re-engineer the address pattern match. @@ -4637,12 +4629,15 @@ bool SWPointer::scaled_iv(Node* n) { int scale = n->in(2)->get_int(); _scale = tmp._scale << scale; _offset += tmp._offset << scale; - _invar = tmp._invar; - if (_invar != nullptr) { - _negate_invar = tmp._negate_invar; - _invar_scale = n->in(2); + if (tmp._invar != nullptr) { + BasicType bt = tmp._invar->bottom_type()->basic_type(); + assert(bt == T_INT || bt == T_LONG, ""); + maybe_add_to_invar(register_if_new(LShiftNode::make(tmp._invar, n->in(2), bt)), false); +#ifdef ASSERT + _debug_invar_scale = n->in(2); +#endif } - NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, _invar, _negate_invar);) + NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, _invar);) return true; } } @@ -4676,41 +4671,34 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { NOT_PRODUCT(_tracer.offset_plus_k_4(n);) return false; } - if (_invar != nullptr) { // already has an invariant - NOT_PRODUCT(_tracer.offset_plus_k_5(n, _invar);) - return false; - } + assert((_debug_invar == nullptr) == (_invar == nullptr), ""); if (_analyze_only && is_loop_member(n)) { _nstack->push(n, _stack_idx++); } if (opc == Op_AddI) { if (n->in(2)->is_Con() && invariant(n->in(1))) { - _negate_invar = negate; - _invar = n->in(1); + maybe_add_to_invar(n->in(1), negate); _offset += negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); - NOT_PRODUCT(_tracer.offset_plus_k_6(n, _invar, _negate_invar, _offset);) + NOT_PRODUCT(_tracer.offset_plus_k_6(n, _invar, negate, _offset);) return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); - _negate_invar = negate; - _invar = n->in(2); - NOT_PRODUCT(_tracer.offset_plus_k_7(n, _invar, _negate_invar, _offset);) + maybe_add_to_invar(n->in(2), negate); + NOT_PRODUCT(_tracer.offset_plus_k_7(n, _invar, negate, _offset);) return true; } } if (opc == Op_SubI) { if (n->in(2)->is_Con() && invariant(n->in(1))) { - _negate_invar = negate; - _invar = n->in(1); + maybe_add_to_invar(n->in(1), negate); _offset += !negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); - NOT_PRODUCT(_tracer.offset_plus_k_8(n, _invar, _negate_invar, _offset);) + NOT_PRODUCT(_tracer.offset_plus_k_8(n, _invar, negate, _offset);) return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); - _negate_invar = !negate; - _invar = n->in(2); - NOT_PRODUCT(_tracer.offset_plus_k_9(n, _invar, _negate_invar, _offset);) + maybe_add_to_invar(n->in(2), !negate); + NOT_PRODUCT(_tracer.offset_plus_k_9(n, _invar, !negate, _offset);) return true; } } @@ -4727,9 +4715,8 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { } // Check if 'n' can really be used as invariant (not in main loop and dominating the pre loop). if (invariant(n)) { - _negate_invar = negate; - _invar = n; - NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, _negate_invar, _offset);) + maybe_add_to_invar(n, negate); + NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, negate, _offset);) return true; } } @@ -4738,6 +4725,67 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { return false; } +Node* SWPointer::maybe_negate_invar(bool negate, Node* invar) { +#ifdef ASSERT + _debug_negate_invar = negate; +#endif + if (negate) { + BasicType bt = invar->bottom_type()->basic_type(); + assert(bt == T_INT || bt == T_LONG, ""); + PhaseIterGVN& igvn = phase()->igvn(); + Node* zero = igvn.zerocon(bt); + phase()->set_ctrl(zero, phase()->C->root()); + Node* sub = SubNode::make(zero, invar, bt); + invar = register_if_new(sub); + } + return invar; +} + +Node* SWPointer::register_if_new(Node* n) const { + PhaseIterGVN& igvn = phase()->igvn(); + Node* prev = igvn.hash_find_insert(n); + if (prev != nullptr) { + n->destruct(&igvn); + n = prev; + } else { + Node* c = phase()->get_early_ctrl(n); + phase()->register_new_node(n, c); + } + return n; +} + +void SWPointer::maybe_add_to_invar(Node* new_invar, bool negate) { + new_invar = maybe_negate_invar(negate, new_invar); + if (_invar == nullptr) { + _invar = new_invar; +#ifdef ASSERT + _debug_invar = new_invar; +#endif + return; + } +#ifdef ASSERT + _debug_invar = NodeSentinel; +#endif + BasicType new_invar_bt = new_invar->bottom_type()->basic_type(); + assert(new_invar_bt == T_INT || new_invar_bt == T_LONG, ""); + BasicType invar_bt = _invar->bottom_type()->basic_type(); + assert(invar_bt == T_INT || invar_bt == T_LONG, ""); + + BasicType bt = (new_invar_bt == T_LONG || invar_bt == T_LONG) ? T_LONG : T_INT; + Node* current_invar = _invar; + if (invar_bt != bt) { + assert(bt == T_LONG && invar_bt == T_INT, ""); + assert(new_invar_bt == bt, ""); + current_invar = register_if_new(new ConvI2LNode(current_invar)); + } else if (new_invar_bt != bt) { + assert(bt == T_LONG && new_invar_bt == T_INT, ""); + assert(invar_bt == bt, ""); + new_invar = register_if_new(new ConvI2LNode(new_invar)); + } + Node* add = AddNode::make(current_invar, new_invar, bt); + _invar = register_if_new(add); +} + //-----------------has_potential_dependence----------------- // Check potential data dependence among all memory accesses. // We require every two accesses (with at least one store) of @@ -4774,7 +4822,7 @@ void SWPointer::print() { _adr != nullptr ? _adr->_idx : 0, _scale, _offset); if (_invar != nullptr) { - tty->print(" invar: %c[%d] << [%d]", _negate_invar?'-':'+', _invar->_idx, _invar_scale->_idx); + tty->print(" invar: [%d]", _invar->_idx); } tty->cr(); #endif @@ -4964,13 +5012,13 @@ void SWPointer::Tracer::scaled_iv_8(Node* n, SWPointer* tmp) { } } -void SWPointer::Tracer::scaled_iv_9(Node* n, int scale, int offset, Node* invar, bool negate_invar) { +void SWPointer::Tracer::scaled_iv_9(Node* n, int scale, int offset, Node* invar) { if(_slp->is_trace_alignment()) { print_depth(); tty->print_cr(" %d SWPointer::scaled_iv: Op_LShiftL PASSED, setting _scale = %d, _offset = %d", n->_idx, scale, offset); print_depth(); tty->print_cr(" \\ SWPointer::scaled_iv: in(1) [%d] is scaled_iv_plus_offset, in(2) [%d] used to scale: _scale = %d, _offset = %d", n->in(1)->_idx, n->in(2)->_idx, scale, offset); if (invar != nullptr) { - print_depth(); tty->print_cr(" \\ SWPointer::scaled_iv: scaled invariant: %c[%d]", (negate_invar?'-':'+'), invar->_idx); + print_depth(); tty->print_cr(" \\ SWPointer::scaled_iv: scaled invariant: [%d]", invar->_idx); } inc_depth(); inc_depth(); print_depth(); n->in(1)->dump(); @@ -5022,7 +5070,7 @@ void SWPointer::Tracer::offset_plus_k_5(Node* n, Node* _invar) { void SWPointer::Tracer::offset_plus_k_6(Node* n, Node* _invar, bool _negate_invar, int _offset) { if(_slp->is_trace_alignment()) { - print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_AddI PASSED, setting _negate_invar = %d, _invar = %d, _offset = %d", + print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_AddI PASSED, setting _debug_negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(2) is Con: ", n->in(2)->_idx); n->in(2)->dump(); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(1) is invariant: ", _invar->_idx); _invar->dump(); @@ -5031,7 +5079,7 @@ void SWPointer::Tracer::offset_plus_k_6(Node* n, Node* _invar, bool _negate_inva void SWPointer::Tracer::offset_plus_k_7(Node* n, Node* _invar, bool _negate_invar, int _offset) { if(_slp->is_trace_alignment()) { - print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_AddI PASSED, setting _negate_invar = %d, _invar = %d, _offset = %d", + print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_AddI PASSED, setting _debug_negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(1) is Con: ", n->in(1)->_idx); n->in(1)->dump(); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(2) is invariant: ", _invar->_idx); _invar->dump(); @@ -5040,7 +5088,7 @@ void SWPointer::Tracer::offset_plus_k_7(Node* n, Node* _invar, bool _negate_inva void SWPointer::Tracer::offset_plus_k_8(Node* n, Node* _invar, bool _negate_invar, int _offset) { if(_slp->is_trace_alignment()) { - print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_SubI is PASSED, setting _negate_invar = %d, _invar = %d, _offset = %d", + print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_SubI is PASSED, setting _debug_negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(2) is Con: ", n->in(2)->_idx); n->in(2)->dump(); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(1) is invariant: ", _invar->_idx); _invar->dump(); @@ -5049,7 +5097,7 @@ void SWPointer::Tracer::offset_plus_k_8(Node* n, Node* _invar, bool _negate_inva void SWPointer::Tracer::offset_plus_k_9(Node* n, Node* _invar, bool _negate_invar, int _offset) { if(_slp->is_trace_alignment()) { - print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_SubI PASSED, setting _negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); + print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: Op_SubI PASSED, setting _debug_negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(1) is Con: ", n->in(1)->_idx); n->in(1)->dump(); print_depth(); tty->print(" \\ %d SWPointer::offset_plus_k: in(2) is invariant: ", _invar->_idx); _invar->dump(); } @@ -5057,7 +5105,7 @@ void SWPointer::Tracer::offset_plus_k_9(Node* n, Node* _invar, bool _negate_inva void SWPointer::Tracer::offset_plus_k_10(Node* n, Node* _invar, bool _negate_invar, int _offset) { if(_slp->is_trace_alignment()) { - print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: PASSED, setting _negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); + print_depth(); tty->print_cr(" %d SWPointer::offset_plus_k: PASSED, setting _debug_negate_invar = %d, _invar = %d, _offset = %d", n->_idx, _negate_invar, _invar->_idx, _offset); print_depth(); tty->print_cr(" \\ %d SWPointer::offset_plus_k: is invariant", n->_idx); } } diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index f07971a5330d9..1317ac9bb8175 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -655,8 +655,11 @@ class SWPointer : public ArenaObj { int _offset; // constant offset (in bytes) Node* _invar; // invariant offset (in bytes), null if none - bool _negate_invar; // if true then use: (0 - _invar) - Node* _invar_scale; // multiplier for invariant +#ifdef ASSERT + Node* _debug_invar; + bool _debug_negate_invar; // if true then use: (0 - _invar) + Node* _debug_invar_scale; // multiplier for invariant +#endif Node_Stack* _nstack; // stack used to record a swpointer trace of variants bool _analyze_only; // Used in loop unrolling only for swpointer trace @@ -698,17 +701,17 @@ class SWPointer : public ArenaObj { MemNode* mem() { return _mem; } int scale_in_bytes() { return _scale; } Node* invar() { return _invar; } - bool negate_invar() { return _negate_invar; } - Node* invar_scale() { return _invar_scale; } int offset_in_bytes() { return _offset; } int memory_size() { return _mem->memory_size(); } Node_Stack* node_stack() { return _nstack; } // Comparable? bool invar_equals(SWPointer& q) { - return (_invar == q._invar && - _invar_scale == q._invar_scale && - _negate_invar == q._negate_invar); + assert(_debug_invar == NodeSentinel || q._debug_invar == NodeSentinel || + (_invar == q._invar) == (_debug_invar == q._debug_invar && + _debug_invar_scale == q._debug_invar_scale && + _debug_negate_invar == q._debug_negate_invar), ""); + return _invar == q._invar; } int cmp(SWPointer& q) { @@ -786,7 +789,7 @@ class SWPointer : public ArenaObj { void scaled_iv_6(Node* n, int scale); void scaled_iv_7(Node* n); void scaled_iv_8(Node* n, SWPointer* tmp); - void scaled_iv_9(Node* n, int _scale, int _offset, Node* _invar, bool _negate_invar); + void scaled_iv_9(Node* n, int _scale, int _offset, Node* _invar); void scaled_iv_10(Node* n); void offset_plus_k_1(Node* n); @@ -803,6 +806,12 @@ class SWPointer : public ArenaObj { } _tracer;//TRacer; #endif + + Node* maybe_negate_invar(bool negate, Node* invar); + + void maybe_add_to_invar(Node* new_invar, bool negate); + + Node* register_if_new(Node* n) const; }; #endif // SHARE_OPTO_SUPERWORD_HPP diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java new file mode 100644 index 0000000000000..c5b5e691a5ca4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMultiInvar.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import jdk.internal.misc.Unsafe; +import java.util.Objects; +import java.util.Random; + +/* + * @test + * @bug 8300257 + * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") + * @summary C2: vectorization fails on some simple Memory Segment loops + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compiler.c2.irTests.TestVectorizationMultiInvar + */ + +public class TestVectorizationMultiInvar { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); + } + + static int size = 1024; + static byte[] byteArray = new byte[size * 8]; + static int[] intArray = new int[size]; + static long[] longArray = new long[size]; + static long baseOffset = 0; + + @Test + @IR(counts = { IRNode.LOAD_VECTOR, ">=1", IRNode.STORE_VECTOR, ">=1" }) + public static void testByteLong1(byte[] dest, long[] src) { + for (int i = 0; i < src.length; i++) { + long j = Objects.checkIndex(i * 8, (long)(src.length * 8)); + UNSAFE.putLongUnaligned(dest, baseOffset + j, src[i]); + } + } + + @Run(test = "testByteLong1") + public static void testByteLong1_runner() { + baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET; + testByteLong1(byteArray, longArray); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR, ">=1", IRNode.STORE_VECTOR, ">=1" }) + public static void testLoopNest1(byte[] dest, byte[] src, + long start1, long stop1, + long start2, long stop2, + long start3, long stop3, + long start4, long stop4, + long start5, long stop5) { + if (src == null || dest == null) { + } + for (long i = start1; i < stop1; i++) { + for (long j = start2; j < stop2; j++) { + for (long k = start3; k < stop3; k++) { + for (long l = start4; l < stop4; l++) { + for (long m = start5; m < stop5; m++) { + long invar = i + j + k + l + m; + for (int n = 0; n < src.length - (int)invar; n++) { + UNSAFE.putByte(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + n + invar, UNSAFE.getByte(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + n + invar)); + } + } + } + } + } + } + } + + @Run(test = "testLoopNest1") + public static void testLoopNest1_runner() { + testLoopNest1(byteArray, byteArray, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR, ">=1", IRNode.STORE_VECTOR, ">=1" }) + public static void testLoopNest2(int[] dest, int[] src, + long start1, long stop1, + long start2, long stop2, + long start3, long stop3, + long start4, long stop4, + long start5, long stop5) { + if (src == null || dest == null) { + } + for (long i = start1; i < stop1; i++) { + for (long j = start2; j < stop2; j++) { + for (long k = start3; k < stop3; k++) { + for (long l = start4; l < stop4; l++) { + for (long m = start5; m < stop5; m++) { + long invar = i + j + k + l + m; + for (int n = 0; n < src.length - (int)invar; n++) { + UNSAFE.putInt(dest, UNSAFE.ARRAY_INT_BASE_OFFSET + (n + invar) * UNSAFE.ARRAY_INT_INDEX_SCALE, UNSAFE.getInt(src, UNSAFE.ARRAY_INT_BASE_OFFSET + (n + invar) * UNSAFE.ARRAY_INT_INDEX_SCALE)); + } + } + } + } + } + } + } + + @Run(test = "testLoopNest2") + public static void testLoopNest2_runner() { + testLoopNest2(intArray, intArray, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2); + } +}