Mercurial > hg > graal-jvmci-8
diff src/share/vm/c1/c1_LIRGenerator.cpp @ 2446:13bc79b5c9c8
7033154: Improve C1 arraycopy performance
Summary: better static analysis. Take advantage of array copy stubs.
Reviewed-by: never
author | roland |
---|---|
date | Sun, 03 Apr 2011 12:00:54 +0200 |
parents | 8033953d67ff |
children | d86923d96dca |
line wrap: on
line diff
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Sat Apr 02 10:54:15 2011 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Sun Apr 03 12:00:54 2011 +0200 @@ -706,6 +706,38 @@ } } +static Value maxvalue(IfOp* ifop) { + switch (ifop->cond()) { + case If::eql: return NULL; + case If::neq: return NULL; + case If::lss: // x < y ? x : y + case If::leq: // x <= y ? x : y + if (ifop->x() == ifop->tval() && + ifop->y() == ifop->fval()) return ifop->y(); + return NULL; + + case If::gtr: // x > y ? y : x + case If::geq: // x >= y ? y : x + if (ifop->x() == ifop->tval() && + ifop->y() == ifop->fval()) return ifop->y(); + return NULL; + + } +} + +static ciType* phi_declared_type(Phi* phi) { + ciType* t = phi->operand_at(0)->declared_type(); + if (t == NULL) { + return NULL; + } + for(int i = 1; i < phi->operand_count(); i++) { + if (t != phi->operand_at(i)->declared_type()) { + return NULL; + } + } + return t; +} + void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** expected_typep) { Instruction* src = x->argument_at(0); Instruction* src_pos = x->argument_at(1); @@ -715,12 +747,20 @@ // first try to identify the likely type of the arrays involved ciArrayKlass* expected_type = NULL; - bool is_exact = false; + bool is_exact = false, src_objarray = false, dst_objarray = false; { ciArrayKlass* src_exact_type = as_array_klass(src->exact_type()); ciArrayKlass* src_declared_type = as_array_klass(src->declared_type()); + Phi* phi; + if (src_declared_type == NULL && (phi = src->as_Phi()) != NULL) { + src_declared_type = as_array_klass(phi_declared_type(phi)); + } ciArrayKlass* dst_exact_type = as_array_klass(dst->exact_type()); ciArrayKlass* dst_declared_type = as_array_klass(dst->declared_type()); + if (dst_declared_type == NULL && (phi = dst->as_Phi()) != NULL) { + dst_declared_type = as_array_klass(phi_declared_type(phi)); + } + if (src_exact_type != NULL && src_exact_type == dst_exact_type) { // the types exactly match so the type is fully known is_exact = true; @@ -744,17 +784,60 @@ if (expected_type == NULL) expected_type = dst_exact_type; if (expected_type == NULL) expected_type = src_declared_type; if (expected_type == NULL) expected_type = dst_declared_type; + + src_objarray = (src_exact_type && src_exact_type->is_obj_array_klass()) || (src_declared_type && src_declared_type->is_obj_array_klass()); + dst_objarray = (dst_exact_type && dst_exact_type->is_obj_array_klass()) || (dst_declared_type && dst_declared_type->is_obj_array_klass()); } // if a probable array type has been identified, figure out if any // of the required checks for a fast case can be elided. int flags = LIR_OpArrayCopy::all_flags; + + if (!src_objarray) + flags &= ~LIR_OpArrayCopy::src_objarray; + if (!dst_objarray) + flags &= ~LIR_OpArrayCopy::dst_objarray; + + if (!x->arg_needs_null_check(0)) + flags &= ~LIR_OpArrayCopy::src_null_check; + if (!x->arg_needs_null_check(2)) + flags &= ~LIR_OpArrayCopy::dst_null_check; + + if (expected_type != NULL) { - // try to skip null checks - if (src->as_NewArray() != NULL) + Value length_limit = NULL; + + IfOp* ifop = length->as_IfOp(); + if (ifop != NULL) { + // look for expressions like min(v, a.length) which ends up as + // x > y ? y : x or x >= y ? y : x + if ((ifop->cond() == If::gtr || ifop->cond() == If::geq) && + ifop->x() == ifop->fval() && + ifop->y() == ifop->tval()) { + length_limit = ifop->y(); + } + } + + // try to skip null checks and range checks + NewArray* src_array = src->as_NewArray(); + if (src_array != NULL) { flags &= ~LIR_OpArrayCopy::src_null_check; - if (dst->as_NewArray() != NULL) + if (length_limit != NULL && + src_array->length() == length_limit && + is_constant_zero(src_pos)) { + flags &= ~LIR_OpArrayCopy::src_range_check; + } + } + + NewArray* dst_array = dst->as_NewArray(); + if (dst_array != NULL) { flags &= ~LIR_OpArrayCopy::dst_null_check; + if (length_limit != NULL && + dst_array->length() == length_limit && + is_constant_zero(dst_pos)) { + flags &= ~LIR_OpArrayCopy::dst_range_check; + } + } // check from incoming constant values if (positive_constant(src_pos)) @@ -788,6 +871,28 @@ } } + IntConstant* src_int = src_pos->type()->as_IntConstant(); + IntConstant* dst_int = dst_pos->type()->as_IntConstant(); + if (src_int && dst_int) { + int s_offs = src_int->value(); + int d_offs = dst_int->value(); + if (src_int->value() >= dst_int->value()) { + flags &= ~LIR_OpArrayCopy::overlapping; + } + if (expected_type != NULL) { + BasicType t = expected_type->element_type()->basic_type(); + int element_size = type2aelembytes(t); + if (((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) && + ((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0)) { + flags &= ~LIR_OpArrayCopy::unaligned; + } + } + } else if (src_pos == dst_pos || is_constant_zero(dst_pos)) { + // src and dest positions are the same, or dst is zero so assume + // nonoverlapping copy. + flags &= ~LIR_OpArrayCopy::overlapping; + } + if (src == dst) { // moving within a single array so no type checks are needed if (flags & LIR_OpArrayCopy::type_check) {