bool ion::ExtractLinearInequality(MTest *test, BranchDirection direction, LinearSum *plhs, MDefinition **prhs, bool *plessEqual) { if (!test->getOperand(0)->isCompare()) return false; MCompare *compare = test->getOperand(0)->toCompare(); MDefinition *lhs = compare->getOperand(0); MDefinition *rhs = compare->getOperand(1); if (compare->specialization() != MIRType_Int32) return false; JS_ASSERT(lhs->type() == MIRType_Int32); JS_ASSERT(rhs->type() == MIRType_Int32); JSOp jsop = compare->jsop(); if (direction == FALSE_BRANCH) jsop = analyze::NegateCompareOp(jsop); LinearSum lsum = ExtractLinearSum(lhs); LinearSum rsum = ExtractLinearSum(rhs); if (!SafeSub(lsum.constant, rsum.constant, &lsum.constant)) return false; // Normalize operations to use <= or >=. switch (jsop) { case JSOP_LE: *plessEqual = true; break; case JSOP_LT: /* x < y ==> x + 1 <= y */ if (!SafeAdd(lsum.constant, 1, &lsum.constant)) return false; *plessEqual = true; break; case JSOP_GE: *plessEqual = false; break; case JSOP_GT: /* x > y ==> x - 1 >= y */ if (!SafeSub(lsum.constant, 1, &lsum.constant)) return false; *plessEqual = false; break; default: return false; } *plhs = lsum; *prhs = rsum.term; return true; }
static void TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool filtersUndefined, MTest *test, BranchDirection direction, bool *eliminated) { JS_ASSERT(filtersNull || filtersUndefined); // Watch for code patterns similar to 'if (x.f) { ... = x.f }'. If x.f // is either an object or null/undefined, there will be a type barrier on // the latter read as the null/undefined value is never realized there. // The type barrier can be eliminated, however, by looking at tests // performed on the result of the first operation that filter out all // types that have been seen in the first access but not the second. // A test 'if (x.f)' filters both null and undefined. if (test->getOperand(0) == barrier->input() && direction == TRUE_BRANCH) { *eliminated = true; barrier->replaceAllUsesWith(barrier->input()); return; } if (!test->getOperand(0)->isCompare()) return; MCompare *compare = test->getOperand(0)->toCompare(); MCompare::CompareType compareType = compare->compareType(); if (compareType != MCompare::Compare_Undefined && compareType != MCompare::Compare_Null) return; if (compare->getOperand(0) != barrier->input()) return; JSOp op = compare->jsop(); JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ || op == JSOP_NE || op == JSOP_STRICTNE); if ((direction == TRUE_BRANCH) != (op == JSOP_NE || op == JSOP_STRICTNE)) return; // A test 'if (x.f != null)' or 'if (x.f != undefined)' filters both null // and undefined. If strict equality is used, only the specified rhs is // tested for. if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) { if (compareType == MCompare::Compare_Undefined && !filtersUndefined) return; if (compareType == MCompare::Compare_Null && !filtersNull) return; } *eliminated = true; barrier->replaceAllUsesWith(barrier->input()); }
bool RangeAnalysis::addBetaNobes() { IonSpew(IonSpew_Range, "Adding beta nobes"); for (PostorderIterator i(graph_.poBegin()); i != graph_.poEnd(); i++) { MBasicBlock *block = *i; IonSpew(IonSpew_Range, "Looking at block %d", block->id()); BranchDirection branch_dir; MTest *test = block->immediateDominatorBranch(&branch_dir); if (!test || !test->getOperand(0)->isCompare()) continue; MCompare *compare = test->getOperand(0)->toCompare(); MDefinition *left = compare->getOperand(0); MDefinition *right = compare->getOperand(1); int32 bound; MDefinition *val = NULL; JSOp jsop = compare->jsop(); if (branch_dir == FALSE_BRANCH) jsop = analyze::NegateCompareOp(jsop); if (left->isConstant() && left->toConstant()->value().isInt32()) { bound = left->toConstant()->value().toInt32(); val = right; jsop = analyze::ReverseCompareOp(jsop); } else if (right->isConstant() && right->toConstant()->value().isInt32()) { bound = right->toConstant()->value().toInt32(); val = left; } else { MDefinition *smaller = NULL; MDefinition *greater = NULL; if (jsop == JSOP_LT) { smaller = left; greater = right; } else if (jsop == JSOP_GT) { smaller = right; greater = left; } if (smaller && greater) { MBeta *beta; beta = MBeta::New(smaller, Range(JSVAL_INT_MIN, JSVAL_INT_MAX-1)); block->insertBefore(*block->begin(), beta); replaceDominatedUsesWith(smaller, beta, block); beta = MBeta::New(greater, Range(JSVAL_INT_MIN+1, JSVAL_INT_MAX)); block->insertBefore(*block->begin(), beta); replaceDominatedUsesWith(greater, beta, block); } continue; } JS_ASSERT(val); Range comp; switch (jsop) { case JSOP_LE: comp.setUpper(bound); break; case JSOP_LT: if (!SafeSub(bound, 1, &bound)) break; comp.setUpper(bound); break; case JSOP_GE: comp.setLower(bound); break; case JSOP_GT: if (!SafeAdd(bound, 1, &bound)) break; comp.setLower(bound); break; case JSOP_EQ: comp.setLower(bound); comp.setUpper(bound); default: break; // well, for neq we could have // [-\inf, bound-1] U [bound+1, \inf] but we only use contiguous ranges. } IonSpew(IonSpew_Range, "Adding beta node for %d", val->id()); MBeta *beta = MBeta::New(val, comp); block->insertBefore(*block->begin(), beta); replaceDominatedUsesWith(val, beta, block); } return true; }