mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-22 12:04:39 +02:00
6395208: Elide autoboxing for calls to HashMap.get(int) and HashMap.get(long)
Reviewed-by: kvn, rasbold
This commit is contained in:
parent
5fa349cc42
commit
10c473e425
16 changed files with 540 additions and 67 deletions
|
@ -543,6 +543,159 @@ Node* IfNode::up_one_dom(Node *curr, bool linear_only) {
|
|||
return NULL; // Dead loop? Or hit root?
|
||||
}
|
||||
|
||||
|
||||
//------------------------------filtered_int_type--------------------------------
|
||||
// Return a possibly more restrictive type for val based on condition control flow for an if
|
||||
const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj) {
|
||||
assert(if_proj &&
|
||||
(if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection");
|
||||
if (if_proj->in(0) && if_proj->in(0)->is_If()) {
|
||||
IfNode* iff = if_proj->in(0)->as_If();
|
||||
if (iff->in(1) && iff->in(1)->is_Bool()) {
|
||||
BoolNode* bol = iff->in(1)->as_Bool();
|
||||
if (bol->in(1) && bol->in(1)->is_Cmp()) {
|
||||
const CmpNode* cmp = bol->in(1)->as_Cmp();
|
||||
if (cmp->in(1) == val) {
|
||||
const TypeInt* cmp2_t = gvn->type(cmp->in(2))->isa_int();
|
||||
if (cmp2_t != NULL) {
|
||||
jint lo = cmp2_t->_lo;
|
||||
jint hi = cmp2_t->_hi;
|
||||
BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate();
|
||||
switch (msk) {
|
||||
case BoolTest::ne:
|
||||
// Can't refine type
|
||||
return NULL;
|
||||
case BoolTest::eq:
|
||||
return cmp2_t;
|
||||
case BoolTest::lt:
|
||||
lo = TypeInt::INT->_lo;
|
||||
if (hi - 1 < hi) {
|
||||
hi = hi - 1;
|
||||
}
|
||||
break;
|
||||
case BoolTest::le:
|
||||
lo = TypeInt::INT->_lo;
|
||||
break;
|
||||
case BoolTest::gt:
|
||||
if (lo + 1 > lo) {
|
||||
lo = lo + 1;
|
||||
}
|
||||
hi = TypeInt::INT->_hi;
|
||||
break;
|
||||
case BoolTest::ge:
|
||||
// lo unchanged
|
||||
hi = TypeInt::INT->_hi;
|
||||
break;
|
||||
}
|
||||
const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen);
|
||||
return rtn_t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------fold_compares----------------------------
|
||||
// See if a pair of CmpIs can be converted into a CmpU. In some cases
|
||||
// the direction of this if is determined by the preciding if so it
|
||||
// can be eliminate entirely. Given an if testing (CmpI n c) check
|
||||
// for an immediately control dependent if that is testing (CmpI n c2)
|
||||
// and has one projection leading to this if and the other projection
|
||||
// leading to a region that merges one of this ifs control
|
||||
// projections.
|
||||
//
|
||||
// If
|
||||
// / |
|
||||
// / |
|
||||
// / |
|
||||
// If |
|
||||
// /\ |
|
||||
// / \ |
|
||||
// / \ |
|
||||
// / Region
|
||||
//
|
||||
Node* IfNode::fold_compares(PhaseGVN* phase) {
|
||||
if (!EliminateAutoBox || Opcode() != Op_If) return NULL;
|
||||
|
||||
Node* this_cmp = in(1)->in(1);
|
||||
if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
|
||||
this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) {
|
||||
Node* ctrl = in(0);
|
||||
BoolNode* this_bool = in(1)->as_Bool();
|
||||
Node* n = this_cmp->in(1);
|
||||
int hi = this_cmp->in(2)->get_int();
|
||||
if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 &&
|
||||
ctrl->in(0)->is_If() &&
|
||||
ctrl->in(0)->outcnt() == 2 &&
|
||||
ctrl->in(0)->in(1)->is_Bool() &&
|
||||
ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI &&
|
||||
ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() &&
|
||||
ctrl->in(0)->in(1)->in(1)->in(1) == n) {
|
||||
IfNode* dom_iff = ctrl->in(0)->as_If();
|
||||
Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con);
|
||||
if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() &&
|
||||
this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) {
|
||||
// Identify which proj goes to the region and which continues on
|
||||
RegionNode* region = otherproj->unique_out()->as_Region();
|
||||
Node* success = NULL;
|
||||
Node* fail = NULL;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Node* proj = proj_out(i);
|
||||
if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) {
|
||||
success = proj;
|
||||
} else if (fail == NULL) {
|
||||
fail = proj;
|
||||
} else {
|
||||
success = fail = NULL;
|
||||
}
|
||||
}
|
||||
if (success != NULL && fail != NULL && !region->has_phi()) {
|
||||
int lo = dom_iff->in(1)->in(1)->in(2)->get_int();
|
||||
BoolNode* dom_bool = dom_iff->in(1)->as_Bool();
|
||||
Node* dom_cmp = dom_bool->in(1);
|
||||
const TypeInt* failtype = filtered_int_type(phase, n, ctrl);
|
||||
if (failtype != NULL) {
|
||||
const TypeInt* type2 = filtered_int_type(phase, n, fail);
|
||||
if (type2 != NULL) {
|
||||
failtype = failtype->join(type2)->is_int();
|
||||
} else {
|
||||
failtype = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (failtype != NULL &&
|
||||
dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) {
|
||||
int bound = failtype->_hi - failtype->_lo + 1;
|
||||
if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) {
|
||||
// Merge the two compares into a single unsigned compare by building (CmpU (n - lo) hi)
|
||||
BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge;
|
||||
Node* adjusted = phase->transform(new (phase->C, 3) SubINode(n, phase->intcon(failtype->_lo)));
|
||||
Node* newcmp = phase->transform(new (phase->C, 3) CmpUNode(adjusted, phase->intcon(bound)));
|
||||
Node* newbool = phase->transform(new (phase->C, 2) BoolNode(newcmp, cond));
|
||||
phase->hash_delete(dom_iff);
|
||||
dom_iff->set_req(1, phase->intcon(ctrl->as_Proj()->_con));
|
||||
phase->is_IterGVN()->_worklist.push(dom_iff);
|
||||
phase->hash_delete(this);
|
||||
set_req(1, newbool);
|
||||
return this;
|
||||
}
|
||||
if (failtype->_lo > failtype->_hi) {
|
||||
// previous if determines the result of this if so
|
||||
// replace Bool with constant
|
||||
phase->hash_delete(this);
|
||||
set_req(1, phase->intcon(success->as_Proj()->_con));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------remove_useless_bool----------------------------
|
||||
// Check for people making a useless boolean: things like
|
||||
// if( (x < y ? true : false) ) { ... }
|
||||
|
@ -744,6 +897,11 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||
// Normal equivalent-test check.
|
||||
if( !dom ) return NULL; // Dead loop?
|
||||
|
||||
Node* result = fold_compares(phase);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Search up the dominator tree for an If with an identical test
|
||||
while( dom->Opcode() != op || // Not same opcode?
|
||||
dom->in(1) != in(1) || // Not same input 1?
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue