# HG changeset patch # User kvn # Date 1345661740 25200 # Node ID 5af51c8822075c8da449dd7ba0e2cc9c84658e5f # Parent 0bfcb7a3e12dbf2d23ca38771cf06d52e42efa2d 7192963: assert(_in[req-1] == this) failed: Must pass arg count to 'new' Summary: Fixed Pack node generation. Not vectorize shift instructions if count is not the same for all shifts and if count is vector. Reviewed-by: twisti diff -r 0bfcb7a3e12d -r 5af51c882207 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Aug 22 14:29:57 2012 +0200 +++ b/src/share/vm/opto/compile.cpp Wed Aug 22 11:55:40 2012 -0700 @@ -2604,7 +2604,7 @@ if (n->req()-1 > 2) { // Replace many operand PackNodes with a binary tree for matching PackNode* p = (PackNode*) n; - Node* btp = p->binaryTreePack(Compile::current(), 1, n->req()); + Node* btp = p->binary_tree_pack(Compile::current(), 1, n->req()); n->subsume_by(btp); } break; diff -r 0bfcb7a3e12d -r 5af51c882207 src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Wed Aug 22 14:29:57 2012 +0200 +++ b/src/share/vm/opto/superword.cpp Wed Aug 22 11:55:40 2012 -0700 @@ -1055,10 +1055,22 @@ // Can code be generated for pack p? bool SuperWord::implemented(Node_List* p) { Node* p0 = p->at(0); - if (VectorNode::is_shift(p0) && in_bb(p0->in(2))) { - return false; // vector shift count should be loop's invariant. + return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0)); +} + +//------------------------------same_inputs-------------------------- +// For pack p, are all idx operands the same? +static bool same_inputs(Node_List* p, int idx) { + Node* p0 = p->at(0); + uint vlen = p->size(); + Node* p0_def = p0->in(idx); + for (uint i = 1; i < vlen; i++) { + Node* pi = p->at(i); + Node* pi_def = pi->in(idx); + if (p0_def != pi_def) + return false; } - return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0)); + return true; } //------------------------------profitable--------------------------- @@ -1066,7 +1078,7 @@ bool SuperWord::profitable(Node_List* p) { Node* p0 = p->at(0); uint start, end; - vector_opd_range(p0, &start, &end); + VectorNode::vector_operands(p0, &start, &end); // Return false if some input is not vector and inside block for (uint i = start; i < end; i++) { @@ -1074,15 +1086,20 @@ // For now, return false if not scalar promotion case (inputs are the same.) // Later, implement PackNode and allow differing, non-vector inputs // (maybe just the ones from outside the block.) - Node* p0_def = p0->in(i); - for (uint j = 1; j < p->size(); j++) { - Node* use = p->at(j); - Node* def = use->in(i); - if (p0_def != def) - return false; + if (!same_inputs(p, i)) { + return false; } } } + if (VectorNode::is_shift(p0)) { + // For now, return false if shift count is vector because + // hw does not support it. + if (is_vector_use(p0, 2)) + return false; + // For the same reason return false if different shift counts. + if (!same_inputs(p, 2)) + return false; + } if (!p0->is_Store()) { // For now, return false if not all uses are vector. // Later, implement ExtractNode and allow non-vector uses (maybe @@ -1395,17 +1412,7 @@ uint vlen = p->size(); Node* opd = p0->in(opd_idx); - bool same_opd = true; - for (uint i = 1; i < vlen; i++) { - Node* pi = p->at(i); - Node* in = pi->in(opd_idx); - if (opd != in) { - same_opd = false; - break; - } - } - - if (same_opd) { + if (same_inputs(p, opd_idx)) { if (opd->is_Vector() || opd->is_LoadVector()) { assert(((opd_idx != 2) || !VectorNode::is_shift(p0)), "shift's count can't be vector"); return opd; // input is matching vector @@ -1468,7 +1475,7 @@ Node* in = pi->in(opd_idx); assert(my_pack(in) == NULL, "Should already have been unpacked"); assert(opd_bt == in->bottom_type()->basic_type(), "all same type"); - pk->add_opd(i, in); + pk->add_opd(in); } _phase->_igvn.register_new_node_with_optimizer(pk); _phase->set_ctrl(pk, _phase->get_ctrl(opd)); @@ -1761,7 +1768,7 @@ const Type* vt = velt_type(n); if (vt->basic_type() == T_INT) { uint start, end; - vector_opd_range(n, &start, &end); + VectorNode::vector_operands(n, &start, &end); const Type* vt = velt_type(n); for (uint j = start; j < end; j++) { @@ -1839,38 +1846,6 @@ return vt1 == vt2; } -//-------------------------vector_opd_range----------------------- -// (Start, end] half-open range defining which operands are vector -void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) { - switch (n->Opcode()) { - case Op_LoadB: case Op_LoadUB: - case Op_LoadS: case Op_LoadUS: - case Op_LoadI: case Op_LoadL: - case Op_LoadF: case Op_LoadD: - case Op_LoadP: - *start = 0; - *end = 0; - return; - case Op_StoreB: case Op_StoreC: - case Op_StoreI: case Op_StoreL: - case Op_StoreF: case Op_StoreD: - case Op_StoreP: - *start = MemNode::ValueIn; - *end = *start + 1; - return; - case Op_LShiftI: case Op_LShiftL: - *start = 1; - *end = 2; - return; - case Op_CMoveI: case Op_CMoveL: case Op_CMoveF: case Op_CMoveD: - *start = 2; - *end = n->req(); - return; - } - *start = 1; - *end = n->req(); // default is all operands -} - //------------------------------in_packset--------------------------- // Are s1 and s2 in a pack pair and ordered as s1,s2? bool SuperWord::in_packset(Node* s1, Node* s2) { diff -r 0bfcb7a3e12d -r 5af51c882207 src/share/vm/opto/vectornode.cpp --- a/src/share/vm/opto/vectornode.cpp Wed Aug 22 14:29:57 2012 +0200 +++ b/src/share/vm/opto/vectornode.cpp Wed Aug 22 11:55:40 2012 -0700 @@ -31,7 +31,7 @@ // Return the vector operator for the specified scalar operation // and vector length. Also used to check if the code generator // supports the vector operation. -int VectorNode::opcode(int sopc, uint vlen, BasicType bt) { +int VectorNode::opcode(int sopc, BasicType bt) { switch (sopc) { case Op_AddI: switch (bt) { @@ -161,7 +161,7 @@ if (is_java_primitive(bt) && (vlen > 1) && is_power_of_2(vlen) && Matcher::vector_size_supported(bt, vlen)) { - int vopc = VectorNode::opcode(opc, vlen, bt); + int vopc = VectorNode::opcode(opc, bt); return vopc > 0 && Matcher::has_match_rule(vopc); } return false; @@ -195,10 +195,54 @@ return false; } +// [Start, end) half-open range defining which operands are vectors +void VectorNode::vector_operands(Node* n, uint* start, uint* end) { + switch (n->Opcode()) { + case Op_LoadB: case Op_LoadUB: + case Op_LoadS: case Op_LoadUS: + case Op_LoadI: case Op_LoadL: + case Op_LoadF: case Op_LoadD: + case Op_LoadP: case Op_LoadN: + *start = 0; + *end = 0; // no vector operands + break; + case Op_StoreB: case Op_StoreC: + case Op_StoreI: case Op_StoreL: + case Op_StoreF: case Op_StoreD: + case Op_StoreP: case Op_StoreN: + *start = MemNode::ValueIn; + *end = MemNode::ValueIn + 1; // 1 vector operand + break; + case Op_LShiftI: case Op_LShiftL: + case Op_RShiftI: case Op_RShiftL: + case Op_URShiftI: case Op_URShiftL: + *start = 1; + *end = 2; // 1 vector operand + break; + case Op_AddI: case Op_AddL: case Op_AddF: case Op_AddD: + case Op_SubI: case Op_SubL: case Op_SubF: case Op_SubD: + case Op_MulI: case Op_MulL: case Op_MulF: case Op_MulD: + case Op_DivF: case Op_DivD: + case Op_AndI: case Op_AndL: + case Op_OrI: case Op_OrL: + case Op_XorI: case Op_XorL: + *start = 1; + *end = 3; // 2 vector operands + break; + case Op_CMoveI: case Op_CMoveL: case Op_CMoveF: case Op_CMoveD: + *start = 2; + *end = n->req(); + break; + default: + *start = 1; + *end = n->req(); // default is all operands + } +} + // Return the vector version of a scalar operation node. VectorNode* VectorNode::make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt) { const TypeVect* vt = TypeVect::make(bt, vlen); - int vopc = VectorNode::opcode(opc, vlen, bt); + int vopc = VectorNode::opcode(opc, bt); switch (vopc) { case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vt); @@ -278,38 +322,39 @@ switch (bt) { case T_BOOLEAN: case T_BYTE: - return new (C, vlen+1) PackBNode(s, vt); + return new (C, 2) PackBNode(s, vt); case T_CHAR: case T_SHORT: - return new (C, vlen+1) PackSNode(s, vt); + return new (C, 2) PackSNode(s, vt); case T_INT: - return new (C, vlen+1) PackINode(s, vt); + return new (C, 2) PackINode(s, vt); case T_LONG: - return new (C, vlen+1) PackLNode(s, vt); + return new (C, 2) PackLNode(s, vt); case T_FLOAT: - return new (C, vlen+1) PackFNode(s, vt); + return new (C, 2) PackFNode(s, vt); case T_DOUBLE: - return new (C, vlen+1) PackDNode(s, vt); + return new (C, 2) PackDNode(s, vt); } ShouldNotReachHere(); return NULL; } // Create a binary tree form for Packs. [lo, hi) (half-open) range -Node* PackNode::binaryTreePack(Compile* C, int lo, int hi) { +PackNode* PackNode::binary_tree_pack(Compile* C, int lo, int hi) { int ct = hi - lo; assert(is_power_of_2(ct), "power of 2"); if (ct == 2) { PackNode* pk = PackNode::make(C, in(lo), 2, vect_type()->element_basic_type()); - pk->add_opd(1, in(lo+1)); + pk->add_opd(in(lo+1)); return pk; } else { int mid = lo + ct/2; - Node* n1 = binaryTreePack(C, lo, mid); - Node* n2 = binaryTreePack(C, mid, hi ); + PackNode* n1 = binary_tree_pack(C, lo, mid); + PackNode* n2 = binary_tree_pack(C, mid, hi ); - BasicType bt = vect_type()->element_basic_type(); + BasicType bt = n1->vect_type()->element_basic_type(); + assert(bt == n2->vect_type()->element_basic_type(), "should be the same"); switch (bt) { case T_BOOLEAN: case T_BYTE: diff -r 0bfcb7a3e12d -r 5af51c882207 src/share/vm/opto/vectornode.hpp --- a/src/share/vm/opto/vectornode.hpp Wed Aug 22 14:29:57 2012 +0200 +++ b/src/share/vm/opto/vectornode.hpp Wed Aug 22 11:55:40 2012 -0700 @@ -56,10 +56,12 @@ static VectorNode* make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt); - static int opcode(int opc, uint vlen, BasicType bt); + static int opcode(int opc, BasicType bt); static bool implemented(int opc, uint vlen, BasicType bt); static bool is_shift(Node* n); static bool is_invariant_vector(Node* n); + // [Start, end) half-open range defining which operands are vectors + static void vector_operands(Node* n, uint* start, uint* end); }; //===========================Vector=ALU=Operations==================================== @@ -440,12 +442,12 @@ PackNode(Node* in1, Node* n2, const TypeVect* vt) : VectorNode(in1, n2, vt) {} virtual int Opcode() const; - void add_opd(uint i, Node* n) { - init_req(i+1, n); + void add_opd(Node* n) { + add_req(n); } // Create a binary tree form for Packs. [lo, hi) (half-open) range - Node* binaryTreePack(Compile* C, int lo, int hi); + PackNode* binary_tree_pack(Compile* C, int lo, int hi); static PackNode* make(Compile* C, Node* s, uint vlen, BasicType bt); }; diff -r 0bfcb7a3e12d -r 5af51c882207 test/compiler/7192963/TestByteVect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7192963/TestByteVect.java Wed Aug 22 11:55:40 2012 -0700 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. 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. + * + */ + +/** + * @test + * @bug 7192963 + * @summary assert(_in[req-1] == this) failed: Must pass arg count to 'new' + * + * @run main/othervm/timeout=400 -Xbatch -Xmx64m TestByteVect + */ + +public class TestByteVect { + private static final int ARRLEN = 997; + private static final int ITERS = 11000; + public static void main(String args[]) { + System.out.println("Testing Byte vectors"); + int errn = test(); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test() { + byte[] a0 = new byte[ARRLEN]; + byte[] a1 = new byte[ARRLEN]; + // Initialize + for (int i=0; i 0) + return errn; + + System.out.println("Time"); + long start, end; + + start = System.currentTimeMillis(); + for (int i=0; i 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test() { + double[] a0 = new double[ARRLEN]; + double[] a1 = new double[ARRLEN]; + // Initialize + for (int i=0; i 0) + return errn; + + System.out.println("Time"); + long start, end; + + start = System.currentTimeMillis(); + for (int i=0; i 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test() { + float[] a0 = new float[ARRLEN]; + float[] a1 = new float[ARRLEN]; + // Initialize + for (int i=0; i 0) + return errn; + + System.out.println("Time"); + long start, end; + + start = System.currentTimeMillis(); + for (int i=0; i 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test() { + int[] a0 = new int[ARRLEN]; + int[] a1 = new int[ARRLEN]; + // Initialize + for (int i=0; i 0) + return errn; + + System.out.println("Time"); + long start, end; + + start = System.currentTimeMillis(); + for (int i=0; i 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test() { + long[] a0 = new long[ARRLEN]; + long[] a1 = new long[ARRLEN]; + // Initialize + for (int i=0; i 0) + return errn; + + System.out.println("Time"); + long start, end; + + start = System.currentTimeMillis(); + for (int i=0; i 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test() { + short[] a0 = new short[ARRLEN]; + short[] a1 = new short[ARRLEN]; + // Initialize + for (int i=0; i 0) + return errn; + + System.out.println("Time"); + long start, end; + + start = System.currentTimeMillis(); + for (int i=0; i