bool BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { MIRType specialization = ins->typePolicySpecialization(); if (specialization == MIRType_None) return BoxInputsPolicy::adjustInputs(alloc, ins); MOZ_ASSERT(ins->type() == specialization); MOZ_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double); // This policy works for both unary and binary bitwise operations. for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition *in = ins->getOperand(i); if (in->type() == MIRType_Int32) continue; MInstruction *replace = MTruncateToInt32::New(alloc, in); ins->block()->insertBefore(ins, replace); ins->replaceOperand(i, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; } return true; }
bool ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { MIRType specialization = ins->typePolicySpecialization(); if (specialization == MIRType_None) return BoxInputsPolicy::adjustInputs(alloc, ins); MOZ_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32); for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition *in = ins->getOperand(i); if (in->type() == ins->type()) continue; MInstruction *replace; if (ins->type() == MIRType_Double) replace = MToDouble::New(alloc, in); else if (ins->type() == MIRType_Float32) replace = MToFloat32::New(alloc, in); else replace = MToInt32::New(alloc, in); ins->block()->insertBefore(ins, replace); ins->replaceOperand(i, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; } return true; }
bool SimdShufflePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { MIRType specialization = ins->typePolicySpecialization(); MSimdGeneralShuffle *s = ins->toSimdGeneralShuffle(); for (unsigned i = 0; i < s->numVectors(); i++) { if (!MaybeSimdUnbox(alloc, ins, specialization, i)) return false; } // Next inputs are the lanes, which need to be int32 for (unsigned i = 0; i < s->numLanes(); i++) { MDefinition *in = ins->getOperand(s->numVectors() + i); if (in->type() == MIRType_Int32) continue; MInstruction *replace = MToInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly); ins->block()->insertBefore(ins, replace); ins->replaceOperand(s->numVectors() + i, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; } return true; }
bool SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MOZ_ASSERT(IsSimdType(ins->type())); MIRType laneType = SimdTypeToLaneType(ins->type()); MDefinition* in = ins->getOperand(Op); // A vector with boolean lanes requires Int32 inputs that have already been // converted to 0/-1. // We can't insert a MIRType_Boolean lane directly - it requires conversion. if (laneType == MIRType_Boolean) { MOZ_ASSERT(in->type() == MIRType_Int32, "Boolean SIMD vector requires Int32 lanes."); return true; } if (in->type() == laneType) return true; MInstruction* replace; if (laneType == MIRType_Int32) { replace = MTruncateToInt32::New(alloc, in); } else { MOZ_ASSERT(laneType == MIRType_Float32); replace = MToFloat32::New(alloc, in); } ins->block()->insertBefore(ins, replace); ins->replaceOperand(Op, replace); return replace->typePolicy()->adjustInputs(alloc, replace); }
bool SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const { MOZ_ASSERT(def->isSameValue()); MSameValue* sameValue = def->toSameValue(); MIRType lhsType = sameValue->lhs()->type(); MIRType rhsType = sameValue->rhs()->type(); // If both operands are numbers, convert them to doubles. if (IsNumberType(lhsType) && IsNumberType(rhsType)) { return AllDoublePolicy::staticAdjustInputs(alloc, def); } // SameValue(Anything, Double) is specialized, so convert the rhs if it's // not already a double. if (lhsType == MIRType::Value && IsNumberType(rhsType)) { if (rhsType != MIRType::Double) { MInstruction* replace = MToDouble::New(alloc, sameValue->rhs()); def->block()->insertBefore(def, replace); def->replaceOperand(1, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) { return false; } } return true; } // Otherwise box both operands. return BoxInputsPolicy::staticAdjustInputs(alloc, def); }
bool TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const { MTypeBarrier* ins = def->toTypeBarrier(); MIRType inputType = ins->getOperand(0)->type(); MIRType outputType = ins->type(); // Input and output type are already in accordance. if (inputType == outputType) { return true; } // Output is a value, currently box the input. if (outputType == MIRType::Value) { // XXX: Possible optimization: decrease resultTypeSet to only include // the inputType. This will remove the need for boxing. MOZ_ASSERT(inputType != MIRType::Value); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); return true; } // Box input if needed. if (inputType != MIRType::Value) { MOZ_ASSERT(ins->alwaysBails()); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); } // We can't unbox a value to null/undefined/lazyargs. So keep output // also a value. // Note: Using setResultType shouldn't be done in TypePolicies, // Here it is fine, since the type barrier has no uses. if (IsNullOrUndefined(outputType) || outputType == MIRType::MagicOptimizedArguments) { MOZ_ASSERT(!ins->hasDefUses()); ins->setResultType(MIRType::Value); return true; } // Unbox / propagate the right type. MUnbox::Mode mode = MUnbox::TypeBarrier; MInstruction* replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); if (!ins->isMovable()) { replace->setNotMovable(); } ins->block()->insertBefore(ins, replace); ins->replaceOperand(0, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) { return false; } // The TypeBarrier is equivalent to removing branches with unexpected // types. The unexpected types would have changed Range Analysis // predictions. As such, we need to prevent destructive optimizations. ins->block()->flagOperandsOfPrunedBranches(replace); return true; }
bool FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { MOZ_ASSERT(ins->numOperands() == 1); MIRType inputType = ins->getOperand(0)->type(); MIRType outputType = ins->type(); // Input and output type are already in accordance. if (inputType == outputType) return true; // Output is a value, box the input. if (outputType == MIRType_Value) { MOZ_ASSERT(inputType != MIRType_Value); ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0))); return true; } // The outputType should be a subset of the inputType else we are in code // that has never executed yet. Bail to see the new type (if that hasn't // happened yet). if (inputType != MIRType_Value) { MBail *bail = MBail::New(alloc); ins->block()->insertBefore(ins, bail); bail->setDependency(ins->dependency()); ins->setDependency(bail); ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0))); } // We can't unbox a value to null/undefined/lazyargs. So keep output // also a value. // Note: Using setResultType shouldn't be done in TypePolicies, // Here it is fine, since the type barrier has no uses. if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) { MOZ_ASSERT(!ins->hasDefUses()); ins->setResultType(MIRType_Value); return true; } // Unbox / propagate the right type. MUnbox::Mode mode = MUnbox::Infallible; MInstruction *replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); ins->block()->insertBefore(ins, replace); ins->replaceOperand(0, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; // Carry over the dependency the MFilterTypeSet had. replace->setDependency(ins->dependency()); return true; }
bool AllDoublePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { for (size_t i = 0, e = ins->numOperands(); i < e; i++) { MDefinition *in = ins->getOperand(i); if (in->type() == MIRType_Double) continue; MInstruction *replace = MToDouble::New(alloc, in); ins->block()->insertBefore(ins, replace); ins->replaceOperand(i, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; } return true; }
bool CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { MCall *call = ins->toCall(); MDefinition *func = call->getFunction(); if (func->type() != MIRType_Object) { MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible); call->block()->insertBefore(call, unbox); call->replaceFunction(unbox); if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false; } for (uint32_t i = 0; i < call->numStackArgs(); i++) EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i)); return true; }
bool SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) { MOZ_ASSERT(IsSimdType(ins->type())); MIRType scalarType = SimdTypeToScalarType(ins->type()); MDefinition *in = ins->getOperand(Op); if (in->type() == scalarType) return true; MInstruction *replace; if (scalarType == MIRType_Int32) { replace = MTruncateToInt32::New(alloc, in); } else { MOZ_ASSERT(scalarType == MIRType_Float32); replace = MToFloat32::New(alloc, in); } ins->block()->insertBefore(ins, replace); ins->replaceOperand(Op, replace); return replace->typePolicy()->adjustInputs(alloc, replace); }
bool ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def) { MOZ_ASSERT(def->isCompare()); MCompare *compare = def->toCompare(); // Convert Float32 operands to doubles for (size_t i = 0; i < 2; i++) { MDefinition *in = def->getOperand(i); if (in->type() == MIRType_Float32) { MInstruction *replace = MToDouble::New(alloc, in); def->block()->insertBefore(def, replace); def->replaceOperand(i, replace); } } // Box inputs to get value if (compare->compareType() == MCompare::Compare_Unknown || compare->compareType() == MCompare::Compare_Value) { return BoxInputsPolicy::adjustInputs(alloc, def); } // Compare_Boolean specialization is done for "Anything === Bool" // If the LHS is boolean, we set the specialization to Compare_Int32. // This matches other comparisons of the form bool === bool and // generated code of Compare_Int32 is more efficient. if (compare->compareType() == MCompare::Compare_Boolean && def->getOperand(0)->type() == MIRType_Boolean) { compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth); } // Compare_Boolean specialization is done for "Anything === Bool" // As of previous line Anything can't be Boolean if (compare->compareType() == MCompare::Compare_Boolean) { // Unbox rhs that is definitely Boolean MDefinition *rhs = def->getOperand(1); if (rhs->type() != MIRType_Boolean) { MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_Boolean, MUnbox::Infallible); def->block()->insertBefore(def, unbox); def->replaceOperand(1, unbox); if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false; } MOZ_ASSERT(def->getOperand(0)->type() != MIRType_Boolean); MOZ_ASSERT(def->getOperand(1)->type() == MIRType_Boolean); return true; } // Compare_StrictString specialization is done for "Anything === String" // If the LHS is string, we set the specialization to Compare_String. if (compare->compareType() == MCompare::Compare_StrictString && def->getOperand(0)->type() == MIRType_String) { compare->setCompareType(MCompare::Compare_String); } // Compare_StrictString specialization is done for "Anything === String" // As of previous line Anything can't be String if (compare->compareType() == MCompare::Compare_StrictString) { // Unbox rhs that is definitely String MDefinition *rhs = def->getOperand(1); if (rhs->type() != MIRType_String) { MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_String, MUnbox::Infallible); def->block()->insertBefore(def, unbox); def->replaceOperand(1, unbox); if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false; } MOZ_ASSERT(def->getOperand(0)->type() != MIRType_String); MOZ_ASSERT(def->getOperand(1)->type() == MIRType_String); return true; } if (compare->compareType() == MCompare::Compare_Undefined || compare->compareType() == MCompare::Compare_Null) { // Nothing to do for undefined and null, lowering handles all types. return true; } // Convert all inputs to the right input type MIRType type = compare->inputType(); MOZ_ASSERT(type == MIRType_Int32 || type == MIRType_Double || type == MIRType_Object || type == MIRType_String || type == MIRType_Float32); for (size_t i = 0; i < 2; i++) { MDefinition *in = def->getOperand(i); if (in->type() == type) continue; MInstruction *replace; switch (type) { case MIRType_Double: { MToFPInstruction::ConversionKind convert = MToFPInstruction::NumbersOnly; if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) convert = MToFPInstruction::NonNullNonStringPrimitives; else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) convert = MToFPInstruction::NonNullNonStringPrimitives; replace = MToDouble::New(alloc, in, convert); break; } case MIRType_Float32: { MToFPInstruction::ConversionKind convert = MToFPInstruction::NumbersOnly; if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) convert = MToFPInstruction::NonNullNonStringPrimitives; else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) convert = MToFPInstruction::NonNullNonStringPrimitives; replace = MToFloat32::New(alloc, in, convert); break; } case MIRType_Int32: { MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly; if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth || (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) || (compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1)) { convert = MacroAssembler::IntConversion_NumbersOrBoolsOnly; } replace = MToInt32::New(alloc, in, convert); break; } case MIRType_Object: replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible); break; case MIRType_String: replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Infallible); break; default: MOZ_CRASH("Unknown compare specialization"); } def->block()->insertBefore(def, replace); def->replaceOperand(i, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; } return true; }
bool FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { MOZ_ASSERT(ins->numOperands() == 1); MIRType inputType = ins->getOperand(0)->type(); MIRType outputType = ins->type(); // Special case when output is a Float32, but input isn't. if (outputType == MIRType_Float32 && inputType != MIRType_Float32) { // Create a MToFloat32 to add between the MFilterTypeSet and // its uses. MInstruction* replace = MToFloat32::New(alloc, ins); ins->justReplaceAllUsesWithExcept(replace); ins->block()->insertAfter(ins, replace); // Reset the type to not MIRType_Float32 // Note: setResultType shouldn't happen in TypePolicies, // Here it is fine, since there is just one use we just // added ourself. And the resulting type after MToFloat32 // equals the original type. ins->setResultType(ins->resultTypeSet()->getKnownMIRType()); outputType = ins->type(); // Do the type analysis if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; // Fall through to let the MFilterTypeSet adjust its input based // on its new type. } // Input and output type are already in accordance. if (inputType == outputType) return true; // Output is a value, box the input. if (outputType == MIRType_Value) { MOZ_ASSERT(inputType != MIRType_Value); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); return true; } // The outputType should be a subset of the inputType else we are in code // that has never executed yet. Bail to see the new type (if that hasn't // happened yet). if (inputType != MIRType_Value) { MBail* bail = MBail::New(alloc); ins->block()->insertBefore(ins, bail); bail->setDependency(ins->dependency()); ins->setDependency(bail); ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); } // We can't unbox a value to null/undefined/lazyargs. So keep output // also a value. // Note: Using setResultType shouldn't be done in TypePolicies, // Here it is fine, since the type barrier has no uses. if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) { MOZ_ASSERT(!ins->hasDefUses()); ins->setResultType(MIRType_Value); return true; } // Unbox / propagate the right type. MUnbox::Mode mode = MUnbox::Infallible; MInstruction* replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); ins->block()->insertBefore(ins, replace); ins->replaceOperand(0, replace); if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false; // Carry over the dependency the MFilterTypeSet had. replace->setDependency(ins->dependency()); return true; }