Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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);
}
Example #11
0
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;
}
Example #12
0
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;
}