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 ComparePolicy::adjustInputs(MInstruction *def) { JS_ASSERT(def->isCompare()); MCompare *compare = def->toCompare(); // Box inputs to get value if (compare->compareType() == MCompare::Compare_Unknown || compare->compareType() == MCompare::Compare_Value) { return BoxInputsPolicy::adjustInputs(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_Int32); } // 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) { if (rhs->type() != MIRType_Value) rhs = boxAt(def, rhs); MInstruction *unbox = MUnbox::New(rhs, MIRType_Boolean, MUnbox::Infallible); def->block()->insertBefore(def, unbox); def->replaceOperand(1, unbox); } JS_ASSERT(def->getOperand(0)->type() != MIRType_Boolean); JS_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) { if (rhs->type() != MIRType_Value) rhs = boxAt(def, rhs); MInstruction *unbox = MUnbox::New(rhs, MIRType_String, MUnbox::Infallible); def->block()->insertBefore(def, unbox); def->replaceOperand(1, unbox); } JS_ASSERT(def->getOperand(0)->type() != MIRType_String); JS_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(); JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double || type == MIRType_Object || type == MIRType_String); for (size_t i = 0; i < 2; i++) { MDefinition *in = def->getOperand(i); if (in->type() == type) continue; MInstruction *replace; // See BinaryArithPolicy::adjustInputs for an explanation of the following if (in->type() == MIRType_Object || in->type() == MIRType_String || in->type() == MIRType_Undefined) { in = boxAt(def, in); } switch (type) { case MIRType_Double: { MToDouble::ConversionKind convert = MToDouble::NumbersOnly; if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) convert = MToDouble::NonNullNonStringPrimitives; else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) convert = MToDouble::NonNullNonStringPrimitives; if (in->type() == MIRType_Null || (in->type() == MIRType_Boolean && convert == MToDouble::NumbersOnly)) { in = boxAt(def, in); } replace = MToDouble::New(in, convert); break; } case MIRType_Int32: replace = MToInt32::New(in); break; case MIRType_Object: replace = MUnbox::New(in, MIRType_Object, MUnbox::Infallible); break; case MIRType_String: replace = MUnbox::New(in, MIRType_String, MUnbox::Infallible); break; default: MOZ_ASSUME_UNREACHABLE("Unknown compare specialization"); } def->block()->insertBefore(def, replace); def->replaceOperand(i, replace); } return true; }