提交 65ed0eab 编写于 作者: K kvn

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
上级 f57ea36f
......@@ -2604,7 +2604,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc ) {
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;
......
......@@ -1055,18 +1055,30 @@ void SuperWord::filter_packs() {
// 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 true;
}
//------------------------------profitable---------------------------
// For pack p, are all operands and all uses (with in the block) vector?
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 @@ bool SuperWord::profitable(Node_List* p) {
// 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 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
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* SuperWord::vector_opd(Node_List* p, int opd_idx) {
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 @@ void SuperWord::compute_vector_element_type() {
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 @@ bool SuperWord::same_velt_type(Node* n1, Node* n2) {
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) {
......
......@@ -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 @@ bool VectorNode::implemented(int opc, uint vlen, BasicType bt) {
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 @@ bool VectorNode::is_invariant_vector(Node* n) {
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 @@ PackNode* PackNode::make(Compile* C, Node* s, uint vlen, BasicType bt) {
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:
......
......@@ -56,10 +56,12 @@ class VectorNode : public TypeNode {
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 @@ class PackNode : public VectorNode {
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);
};
......
/*
* 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<ARRLEN; i++) {
a1[i] = (byte)i;
}
System.out.println("Warmup");
for (int i=0; i<ITERS; i++) {
test_init(a0);
test_addi(a0, a1);
test_lsai(a0, a1);
test_unrl_init(a0);
test_unrl_addi(a0, a1);
test_unrl_lsai(a0, a1);
}
// Test and verify results
System.out.println("Verification");
int errn = 0;
{
test_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_init: ", i, a0[i], (byte)(i&3));
}
test_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_addi: ", i, a0[i], (byte)(i+(i&3)));
}
test_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_lsai: ", i, a0[i], (byte)(i<<(i&3)));
}
test_unrl_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_init: ", i, a0[i], (byte)(i&3));
}
test_unrl_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_addi: ", i, a0[i], (byte)(i+(i&3)));
}
test_unrl_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_lsai: ", i, a0[i], (byte)(i<<(i&3)));
}
}
if (errn > 0)
return errn;
System.out.println("Time");
long start, end;
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_lsai: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_lsai: " + (end - start));
return errn;
}
static void test_init(byte[] a0) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (byte)(i&3);
}
}
static void test_addi(byte[] a0, byte[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (byte)(a1[i]+(i&3));
}
}
static void test_lsai(byte[] a0, byte[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (byte)(a1[i]<<(i&3));
}
}
static void test_unrl_init(byte[] a0) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = 0;
a0[i+1] = 1;
a0[i+2] = 2;
a0[i+3] = 3;
}
for (; i < a0.length; i++) {
a0[i] = (byte)(i&3);
}
}
static void test_unrl_addi(byte[] a0, byte[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = (byte)(a1[i+0]+0);
a0[i+1] = (byte)(a1[i+1]+1);
a0[i+2] = (byte)(a1[i+2]+2);
a0[i+3] = (byte)(a1[i+3]+3);
}
for (; i < a0.length; i++) {
a0[i] = (byte)(a1[i]+(i&3));
}
}
static void test_unrl_lsai(byte[] a0, byte[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = (byte)(a1[i+0]<<0);
a0[i+1] = (byte)(a1[i+1]<<1);
a0[i+2] = (byte)(a1[i+2]<<2);
a0[i+3] = (byte)(a1[i+3]<<3);
}
for (; i < a0.length; i++) {
a0[i] = (byte)(a1[i]<<(i&3));
}
}
static int verify(String text, int i, byte elem, byte val) {
if (elem != val) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
return 1;
}
return 0;
}
}
/*
* 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 TestDoubleVect
*/
public class TestDoubleVect {
private static final int ARRLEN = 997;
private static final int ITERS = 11000;
public static void main(String args[]) {
System.out.println("Testing Double vectors");
int errn = test();
if (errn > 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<ARRLEN; i++) {
a1[i] = (double)i;
}
System.out.println("Warmup");
for (int i=0; i<ITERS; i++) {
test_init(a0);
test_addi(a0, a1);
test_divi(a0, a1);
test_unrl_init(a0);
test_unrl_addi(a0, a1);
test_unrl_divi(a0, a1);
}
// Test and verify results
System.out.println("Verification");
int errn = 0;
{
test_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_init: ", i, a0[i], (double)(i&3));
}
test_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_addi: ", i, a0[i], (double)(i+(i&3)));
}
test_divi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_divi: ", i, a0[i], (double)i/(double)((i&3)+1));
}
test_unrl_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_init: ", i, a0[i], (double)(i&3));
}
test_unrl_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_addi: ", i, a0[i], (double)(i+(i&3)));
}
test_unrl_divi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_divi: ", i, a0[i], (double)i/(double)((i&3)+1));
}
}
if (errn > 0)
return errn;
System.out.println("Time");
long start, end;
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_divi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_divi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_divi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_divi: " + (end - start));
return errn;
}
static void test_init(double[] a0) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (double)(i&3);
}
}
static void test_addi(double[] a0, double[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = a1[i]+(double)(i&3);
}
}
static void test_divi(double[] a0, double[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = a1[i]/(double)((i&3)+1);
}
}
static void test_unrl_init(double[] a0) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = 0.;
a0[i+1] = 1.;
a0[i+2] = 2.;
a0[i+3] = 3.;
}
for (; i < a0.length; i++) {
a0[i] = (double)(i&3);
}
}
static void test_unrl_addi(double[] a0, double[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = a1[i+0]+0.;
a0[i+1] = a1[i+1]+1.;
a0[i+2] = a1[i+2]+2.;
a0[i+3] = a1[i+3]+3.;
}
for (; i < a0.length; i++) {
a0[i] = a1[i]+(double)(i&3);
}
}
static void test_unrl_divi(double[] a0, double[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = a1[i+0]/1.;
a0[i+1] = a1[i+1]/2.;
a0[i+2] = a1[i+2]/3.;
a0[i+3] = a1[i+3]/4.;
}
for (; i < a0.length; i++) {
a0[i] = a1[i]/(double)((i&3)+1);
}
}
static int verify(String text, int i, double elem, double val) {
if (elem != val) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
return 1;
}
return 0;
}
}
/*
* 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 TestFloatVect
*/
public class TestFloatVect {
private static final int ARRLEN = 997;
private static final int ITERS = 11000;
public static void main(String args[]) {
System.out.println("Testing Float vectors");
int errn = test();
if (errn > 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<ARRLEN; i++) {
a1[i] = (float)i;
}
System.out.println("Warmup");
for (int i=0; i<ITERS; i++) {
test_init(a0);
test_addi(a0, a1);
test_divi(a0, a1);
test_unrl_init(a0);
test_unrl_addi(a0, a1);
test_unrl_divi(a0, a1);
}
// Test and verify results
System.out.println("Verification");
int errn = 0;
{
test_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_init: ", i, a0[i], (float)(i&3));
}
test_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_addi: ", i, a0[i], (float)(i+(i&3)));
}
test_divi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_divi: ", i, a0[i], (float)i/(float)((i&3)+1));
}
test_unrl_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_init: ", i, a0[i], (float)(i&3));
}
test_unrl_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_addi: ", i, a0[i], (float)(i+(i&3)));
}
test_unrl_divi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_divi: ", i, a0[i], (float)i/(float)((i&3)+1));
}
}
if (errn > 0)
return errn;
System.out.println("Time");
long start, end;
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_divi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_divi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_divi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_divi: " + (end - start));
return errn;
}
static void test_init(float[] a0) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (float)(i&3);
}
}
static void test_addi(float[] a0, float[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = a1[i]+(float)(i&3);
}
}
static void test_divi(float[] a0, float[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = a1[i]/(float)((i&3)+1);
}
}
static void test_unrl_init(float[] a0) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = 0.f;
a0[i+1] = 1.f;
a0[i+2] = 2.f;
a0[i+3] = 3.f;
}
for (; i < a0.length; i++) {
a0[i] = (float)(i&3);
}
}
static void test_unrl_addi(float[] a0, float[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = a1[i+0]+0.f;
a0[i+1] = a1[i+1]+1.f;
a0[i+2] = a1[i+2]+2.f;
a0[i+3] = a1[i+3]+3.f;
}
for (; i < a0.length; i++) {
a0[i] = a1[i]+(float)(i&3);
}
}
static void test_unrl_divi(float[] a0, float[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = a1[i+0]/1.f;
a0[i+1] = a1[i+1]/2.f;
a0[i+2] = a1[i+2]/3.f;
a0[i+3] = a1[i+3]/4.f;
}
for (; i < a0.length; i++) {
a0[i] = a1[i]/(float)((i&3)+1);
}
}
static int verify(String text, int i, float elem, float val) {
if (elem != val) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
return 1;
}
return 0;
}
}
/*
* 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 TestIntVect
*/
public class TestIntVect {
private static final int ARRLEN = 997;
private static final int ITERS = 11000;
public static void main(String args[]) {
System.out.println("Testing Integer vectors");
int errn = test();
if (errn > 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<ARRLEN; i++) {
a1[i] = i;
}
System.out.println("Warmup");
for (int i=0; i<ITERS; i++) {
test_init(a0);
test_addi(a0, a1);
test_lsai(a0, a1);
test_unrl_init(a0);
test_unrl_addi(a0, a1);
test_unrl_lsai(a0, a1);
}
// Test and verify results
System.out.println("Verification");
int errn = 0;
{
test_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_init: ", i, a0[i], (i&3));
}
test_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_addi: ", i, a0[i], (i+(i&3)));
}
test_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_lsai: ", i, a0[i], (i<<(i&3)));
}
test_unrl_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_init: ", i, a0[i], (i&3));
}
test_unrl_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_addi: ", i, a0[i], (i+(i&3)));
}
test_unrl_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_lsai: ", i, a0[i], (i<<(i&3)));
}
}
if (errn > 0)
return errn;
System.out.println("Time");
long start, end;
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_lsai: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_lsai: " + (end - start));
return errn;
}
static void test_init(int[] a0) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (i&3);
}
}
static void test_addi(int[] a0, int[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = a1[i]+(i&3);
}
}
static void test_lsai(int[] a0, int[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = a1[i]<<(i&3);
}
}
static void test_unrl_init(int[] a0) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = 0;
a0[i+1] = 1;
a0[i+2] = 2;
a0[i+3] = 3;
}
for (; i < a0.length; i++) {
a0[i] = (i&3);
}
}
static void test_unrl_addi(int[] a0, int[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = a1[i+0]+0;
a0[i+1] = a1[i+1]+1;
a0[i+2] = a1[i+2]+2;
a0[i+3] = a1[i+3]+3;
}
for (; i < a0.length; i++) {
a0[i] = a1[i]+(i&3);
}
}
static void test_unrl_lsai(int[] a0, int[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = a1[i+0]<<0;
a0[i+1] = a1[i+1]<<1;
a0[i+2] = a1[i+2]<<2;
a0[i+3] = a1[i+3]<<3;
}
for (; i < a0.length; i++) {
a0[i] = a1[i]<<(i&3);
}
}
static int verify(String text, int i, int elem, int val) {
if (elem != val) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
return 1;
}
return 0;
}
}
/*
* 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 TestLongVect
*/
public class TestLongVect {
private static final int ARRLEN = 997;
private static final int ITERS = 11000;
public static void main(String args[]) {
System.out.println("Testing Long vectors");
int errn = test();
if (errn > 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<ARRLEN; i++) {
a1[i] = (long)i;
}
System.out.println("Warmup");
for (int i=0; i<ITERS; i++) {
test_init(a0);
test_addi(a0, a1);
test_lsai(a0, a1);
test_unrl_init(a0);
test_unrl_addi(a0, a1);
test_unrl_lsai(a0, a1);
}
// Test and verify results
System.out.println("Verification");
int errn = 0;
{
test_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_init: ", i, a0[i], (long)(i&3));
}
test_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_addi: ", i, a0[i], (long)(i+(i&3)));
}
test_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_lsai: ", i, a0[i], (long)(i<<(i&3)));
}
test_unrl_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_init: ", i, a0[i], (long)(i&3));
}
test_unrl_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_addi: ", i, a0[i], (long)(i+(i&3)));
}
test_unrl_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_lsai: ", i, a0[i], (long)(i<<(i&3)));
}
}
if (errn > 0)
return errn;
System.out.println("Time");
long start, end;
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_lsai: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_lsai: " + (end - start));
return errn;
}
static void test_init(long[] a0) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (long)(i&3);
}
}
static void test_addi(long[] a0, long[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (long)(a1[i]+(i&3));
}
}
static void test_lsai(long[] a0, long[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (long)(a1[i]<<(i&3));
}
}
static void test_unrl_init(long[] a0) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = 0;
a0[i+1] = 1;
a0[i+2] = 2;
a0[i+3] = 3;
}
for (; i < a0.length; i++) {
a0[i] = (long)(i&3);
}
}
static void test_unrl_addi(long[] a0, long[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = (long)(a1[i+0]+0);
a0[i+1] = (long)(a1[i+1]+1);
a0[i+2] = (long)(a1[i+2]+2);
a0[i+3] = (long)(a1[i+3]+3);
}
for (; i < a0.length; i++) {
a0[i] = (long)(a1[i]+(i&3));
}
}
static void test_unrl_lsai(long[] a0, long[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = (long)(a1[i+0]<<0);
a0[i+1] = (long)(a1[i+1]<<1);
a0[i+2] = (long)(a1[i+2]<<2);
a0[i+3] = (long)(a1[i+3]<<3);
}
for (; i < a0.length; i++) {
a0[i] = (long)(a1[i]<<(i&3));
}
}
static int verify(String text, int i, long elem, long val) {
if (elem != val) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
return 1;
}
return 0;
}
}
/*
* 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 TestShortVect
*/
public class TestShortVect {
private static final int ARRLEN = 997;
private static final int ITERS = 11000;
public static void main(String args[]) {
System.out.println("Testing Short vectors");
int errn = test();
if (errn > 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<ARRLEN; i++) {
a1[i] = (short)i;
}
System.out.println("Warmup");
for (int i=0; i<ITERS; i++) {
test_init(a0);
test_addi(a0, a1);
test_lsai(a0, a1);
test_unrl_init(a0);
test_unrl_addi(a0, a1);
test_unrl_lsai(a0, a1);
}
// Test and verify results
System.out.println("Verification");
int errn = 0;
{
test_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_init: ", i, a0[i], (short)(i&3));
}
test_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_addi: ", i, a0[i], (short)(i+(i&3)));
}
test_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_lsai: ", i, a0[i], (short)(i<<(i&3)));
}
test_unrl_init(a0);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_init: ", i, a0[i], (short)(i&3));
}
test_unrl_addi(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_addi: ", i, a0[i], (short)(i+(i&3)));
}
test_unrl_lsai(a0, a1);
for (int i=0; i<ARRLEN; i++) {
errn += verify("test_unrl_lsai: ", i, a0[i], (short)(i<<(i&3)));
}
}
if (errn > 0)
return errn;
System.out.println("Time");
long start, end;
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_lsai: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_init(a0);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_init: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_addi(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_addi: " + (end - start));
start = System.currentTimeMillis();
for (int i=0; i<ITERS; i++) {
test_unrl_lsai(a0, a1);
}
end = System.currentTimeMillis();
System.out.println("test_unrl_lsai: " + (end - start));
return errn;
}
static void test_init(short[] a0) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (short)(i&3);
}
}
static void test_addi(short[] a0, short[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (short)(a1[i]+(i&3));
}
}
static void test_lsai(short[] a0, short[] a1) {
for (int i = 0; i < a0.length; i+=1) {
a0[i] = (short)(a1[i]<<(i&3));
}
}
static void test_unrl_init(short[] a0) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = 0;
a0[i+1] = 1;
a0[i+2] = 2;
a0[i+3] = 3;
}
for (; i < a0.length; i++) {
a0[i] = (short)(i&3);
}
}
static void test_unrl_addi(short[] a0, short[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = (short)(a1[i+0]+0);
a0[i+1] = (short)(a1[i+1]+1);
a0[i+2] = (short)(a1[i+2]+2);
a0[i+3] = (short)(a1[i+3]+3);
}
for (; i < a0.length; i++) {
a0[i] = (short)(a1[i]+(i&3));
}
}
static void test_unrl_lsai(short[] a0, short[] a1) {
int i = 0;
for (; i < a0.length-4; i+=4) {
a0[i+0] = (short)(a1[i+0]<<0);
a0[i+1] = (short)(a1[i+1]<<1);
a0[i+2] = (short)(a1[i+2]<<2);
a0[i+3] = (short)(a1[i+3]<<3);
}
for (; i < a0.length; i++) {
a0[i] = (short)(a1[i]<<(i&3));
}
}
static int verify(String text, int i, short elem, short val) {
if (elem != val) {
System.err.println(text + "[" + i + "] = " + elem + " != " + val);
return 1;
}
return 0;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册