static void UnboxSimdPhi(const JitCompartment* jitCompartment, MIRGraph& graph, MPhi* phi, SimdType unboxType) { TempAllocator& alloc = graph.alloc(); // Unbox and replace all operands. for (size_t i = 0, e = phi->numOperands(); i < e; i++) { MDefinition* op = phi->getOperand(i); MSimdUnbox* unbox = MSimdUnbox::New(alloc, op, unboxType); op->block()->insertAtEnd(unbox); phi->replaceOperand(i, unbox); } // Change the MIRType of the Phi. MIRType mirType = SimdTypeToMIRType(unboxType); phi->setResultType(mirType); MBasicBlock* phiBlock = phi->block(); MInstruction* atRecover = phiBlock->safeInsertTop(nullptr, MBasicBlock::IgnoreRecover); MInstruction* at = phiBlock->safeInsertTop(atRecover); // Note, we capture the uses-list now, as new instructions are not visited. MUseIterator i(phi->usesBegin()), e(phi->usesEnd()); // Add a MSimdBox, and replace all the Phi uses with it. JSObject* templateObject = jitCompartment->maybeGetSimdTemplateObjectFor(unboxType); InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>(); MSimdBox* recoverBox = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap); recoverBox->setRecoveredOnBailout(); phiBlock->insertBefore(atRecover, recoverBox); MSimdBox* box = nullptr; while (i != e) { MUse* use = *i++; MNode* ins = use->consumer(); if ((ins->isDefinition() && ins->toDefinition()->isRecoveredOnBailout()) || (ins->isResumePoint() && ins->toResumePoint()->isRecoverableOperand(use))) { use->replaceProducer(recoverBox); continue; } if (!box) { box = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap); phiBlock->insertBefore(at, box); } use->replaceProducer(box); } }
void AdjustTruncatedInputs(MInstruction *truncated) { MBasicBlock *block = truncated->block(); for (size_t i = 0; i < truncated->numOperands(); i++) { if (!truncated->isOperandTruncated(i)) continue; if (truncated->getOperand(i)->type() == MIRType_Int32) continue; MTruncateToInt32 *op = MTruncateToInt32::New(truncated->getOperand(i)); block->insertBefore(truncated, op); truncated->replaceOperand(i, op); } if (truncated->isToDouble()) { truncated->replaceAllUsesWith(truncated->getOperand(0)); block->discard(truncated); } }
void TypeAnalyzer::replaceRedundantPhi(MPhi *phi) { MBasicBlock *block = phi->block(); js::Value v; switch (phi->type()) { case MIRType_Undefined: v = UndefinedValue(); break; case MIRType_Null: v = NullValue(); break; case MIRType_Magic: v = MagicValue(JS_OPTIMIZED_ARGUMENTS); break; default: JS_NOT_REACHED("unexpected type"); return; } MConstant *c = MConstant::New(v); // The instruction pass will insert the box block->insertBefore(*(block->begin()), c); phi->replaceAllUsesWith(c); }
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; }
bool RangeAnalysis::tryHoistBoundsCheck(MBasicBlock *header, MBoundsCheck *ins) { // The bounds check's length must be loop invariant. if (ins->length()->block()->isMarked()) return false; // The bounds check's index should not be loop invariant (else we would // already have hoisted it during LICM). SimpleLinearSum index = ExtractLinearSum(ins->index()); if (!index.term || !index.term->block()->isMarked()) return false; // Check for a symbolic lower and upper bound on the index. If either // condition depends on an iteration bound for the loop, only hoist if // the bounds check is dominated by the iteration bound's test. if (!index.term->range()) return false; const SymbolicBound *lower = index.term->range()->symbolicLower(); if (!lower || !SymbolicBoundIsValid(header, ins, lower)) return false; const SymbolicBound *upper = index.term->range()->symbolicUpper(); if (!upper || !SymbolicBoundIsValid(header, ins, upper)) return false; MBasicBlock *preLoop = header->loopPredecessor(); JS_ASSERT(!preLoop->isMarked()); MDefinition *lowerTerm = ConvertLinearSum(preLoop, lower->sum); if (!lowerTerm) return false; MDefinition *upperTerm = ConvertLinearSum(preLoop, upper->sum); if (!upperTerm) return false; // We are checking that index + indexConstant >= 0, and know that // index >= lowerTerm + lowerConstant. Thus, check that: // // lowerTerm + lowerConstant + indexConstant >= 0 // lowerTerm >= -lowerConstant - indexConstant int32_t lowerConstant = 0; if (!SafeSub(lowerConstant, index.constant, &lowerConstant)) return false; if (!SafeSub(lowerConstant, lower->sum.constant(), &lowerConstant)) return false; MBoundsCheckLower *lowerCheck = MBoundsCheckLower::New(lowerTerm); lowerCheck->setMinimum(lowerConstant); // We are checking that index < boundsLength, and know that // index <= upperTerm + upperConstant. Thus, check that: // // upperTerm + upperConstant < boundsLength int32_t upperConstant = index.constant; if (!SafeAdd(upper->sum.constant(), upperConstant, &upperConstant)) return false; MBoundsCheck *upperCheck = MBoundsCheck::New(upperTerm, ins->length()); upperCheck->setMinimum(upperConstant); upperCheck->setMaximum(upperConstant); // Hoist the loop invariant upper and lower bounds checks. preLoop->insertBefore(preLoop->lastIns(), lowerCheck); preLoop->insertBefore(preLoop->lastIns(), upperCheck); return true; }