void CodeGeneratorX86::visitCompareI64(LCompareI64* lir) { MCompare* mir = lir->mir(); MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 || mir->compareType() == MCompare::Compare_UInt64); const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs); const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs); Register64 lhsRegs = ToRegister64(lhs); Register output = ToRegister(lir->output()); bool isSigned = mir->compareType() == MCompare::Compare_Int64; Assembler::Condition condition = JSOpToCondition(lir->jsop(), isSigned); Label done; masm.move32(Imm32(1), output); if (IsConstant(rhs)) { Imm64 imm = Imm64(ToInt64(rhs)); masm.branch64(condition, lhsRegs, imm, &done); } else { Register64 rhsRegs = ToRegister64(rhs); masm.branch64(condition, lhsRegs, rhsRegs, &done); } masm.xorl(output, output); masm.bind(&done); }
bool CodeGeneratorX86::visitCompareB(LCompareB *lir) { MCompare *mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareB::Lhs); const LAllocation *rhs = lir->rhs(); const Register output = ToRegister(lir->output()); JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); Label notBoolean, done; masm.branchTestBoolean(Assembler::NotEqual, lhs, ¬Boolean); { if (rhs->isConstant()) masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean())); else masm.cmp32(lhs.payloadReg(), ToRegister(rhs)); masm.emitSet(JSOpToCondition(mir->jsop()), output); masm.jump(&done); } masm.bind(¬Boolean); { masm.move32(Imm32(mir->jsop() == JSOP_STRICTNE), output); } masm.bind(&done); return true; }
void CodeGeneratorX86::visitCompareI64AndBranch(LCompareI64AndBranch* lir) { MCompare* mir = lir->cmpMir(); MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 || mir->compareType() == MCompare::Compare_UInt64); const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs); const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs); Register64 lhsRegs = ToRegister64(lhs); bool isSigned = mir->compareType() == MCompare::Compare_Int64; Assembler::Condition condition = JSOpToCondition(lir->jsop(), isSigned); Label* trueLabel = getJumpLabelForBranch(lir->ifTrue()); Label* falseLabel = getJumpLabelForBranch(lir->ifFalse()); if (isNextBlock(lir->ifFalse()->lir())) { falseLabel = nullptr; } else if (isNextBlock(lir->ifTrue()->lir())) { condition = Assembler::InvertCondition(condition); trueLabel = falseLabel; falseLabel = nullptr; } if (IsConstant(rhs)) { Imm64 imm = Imm64(ToInt64(rhs)); masm.branch64(condition, lhsRegs, imm, trueLabel, falseLabel); } else { Register64 rhsRegs = ToRegister64(rhs); masm.branch64(condition, lhsRegs, rhsRegs, trueLabel, falseLabel); } }
void CodeGeneratorX86::visitCompareBitwise(LCompareBitwise* lir) { MCompare* mir = lir->mir(); Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop()); const ValueOperand lhs = ToValue(lir, LCompareBitwise::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareBitwise::RhsInput); const Register output = ToRegister(lir->output()); MOZ_ASSERT(IsEqualityOp(mir->jsop())); Label notEqual, done; masm.cmp32(lhs.typeReg(), rhs.typeReg()); masm.j(Assembler::NotEqual, ¬Equal); { masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); masm.emitSet(cond, output); masm.jump(&done); } masm.bind(¬Equal); { masm.move32(Imm32(cond == Assembler::NotEqual), output); } masm.bind(&done); }
bool CodeGeneratorX86Shared::visitCompare(LCompare *comp) { MCompare *mir = comp->mir(); emitCompare(mir->compareType(), comp->left(), comp->right()); masm.emitSet(JSOpToCondition(mir->compareType(), comp->jsop()), ToRegister(comp->output())); return true; }
bool CodeGeneratorX86Shared::visitCompareAndBranch(LCompareAndBranch *comp) { MCompare *mir = comp->mir(); emitCompare(mir->compareType(), comp->left(), comp->right()); Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop()); emitBranch(cond, comp->ifTrue(), comp->ifFalse()); return true; }
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; }
void CodeGeneratorMIPS64::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir) { MCompare* mir = lir->cmpMir(); Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop()); const ValueOperand lhs = ToValue(lir, LCompareBitwiseAndBranch::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareBitwiseAndBranch::RhsInput); MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); emitBranch(lhs.valueReg(), rhs.valueReg(), cond, lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorX64::visitCompareBitwise(LCompareBitwise* lir) { MCompare* mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareBitwise::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareBitwise::RhsInput); const Register output = ToRegister(lir->output()); MOZ_ASSERT(IsEqualityOp(mir->jsop())); masm.cmpPtr(lhs.valueReg(), rhs.valueReg()); masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); }
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 CodeGeneratorX64::visitCompareV(LCompareV *lir) { MCompare *mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); const Register output = ToRegister(lir->output()); JS_ASSERT(IsEqualityOp(mir->jsop())); masm.cmpq(lhs.valueReg(), rhs.valueReg()); masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); return true; }
void CodeGeneratorX64::visitCompareVAndBranch(LCompareVAndBranch *lir) { MCompare *mir = lir->cmpMir(); const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); masm.cmpPtr(lhs.valueReg(), rhs.valueReg()); emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorMIPS::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir) { MCompare* mir = lir->cmpMir(); Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop()); const ValueOperand lhs = ToValue(lir, LCompareBitwiseAndBranch::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareBitwiseAndBranch::RhsInput); MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); MBasicBlock* notEqual = (cond == Assembler::Equal) ? lir->ifFalse() : lir->ifTrue(); branchToBlock(lhs.typeReg(), rhs.typeReg(), notEqual, Assembler::NotEqual); emitBranch(lhs.payloadReg(), rhs.payloadReg(), cond, lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorX64::visitCompare64AndBranch(LCompare64AndBranch* lir) { MCompare* mir = lir->cmpMir(); MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 || mir->compareType() == MCompare::Compare_UInt64); Register lhs = ToRegister(lir->getOperand(0)); const LAllocation* rhs = lir->getOperand(1); if (rhs->isConstant()) masm.cmpPtr(lhs, ImmWord(ToInt64(rhs))); else masm.cmpPtr(lhs, ToOperand(rhs)); bool isSigned = mir->compareType() == MCompare::Compare_Int64; emitBranch(JSOpToCondition(lir->jsop(), isSigned), lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorMIPS64::visitCompareBAndBranch(LCompareBAndBranch* lir) { MCompare* mir = lir->cmpMir(); const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); const LAllocation* rhs = lir->rhs(); MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); // Load boxed boolean in ScratchRegister. if (rhs->isConstant()) masm.moveValue(rhs->toConstant()->toJSValue(), ScratchRegister); else masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchRegister); // Perform the comparison. Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop()); emitBranch(lhs.valueReg(), ScratchRegister, cond, lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorX64::visitCompareI64AndBranch(LCompareI64AndBranch* lir) { MCompare* mir = lir->cmpMir(); MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 || mir->compareType() == MCompare::Compare_UInt64); LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs); LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs); Register lhsReg = ToRegister64(lhs).reg; if (IsConstant(rhs)) masm.cmpPtr(lhsReg, ImmWord(ToInt64(rhs))); else masm.cmpPtr(lhsReg, ToOperand64(rhs)); bool isSigned = mir->compareType() == MCompare::Compare_Int64; emitBranch(JSOpToCondition(lir->jsop(), isSigned), lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorX64::visitCompareI64(LCompareI64* lir) { MCompare* mir = lir->mir(); MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 || mir->compareType() == MCompare::Compare_UInt64); const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs); const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs); Register lhsReg = ToRegister64(lhs).reg; Register output = ToRegister(lir->output()); if (IsConstant(rhs)) masm.cmpPtr(lhsReg, ImmWord(ToInt64(rhs))); else masm.cmpPtr(lhsReg, ToOperand64(rhs)); bool isSigned = mir->compareType() == MCompare::Compare_Int64; masm.emitSet(JSOpToCondition(lir->jsop(), isSigned), output); }
bool CodeGeneratorX64::visitCompareBAndBranch(LCompareBAndBranch *lir) { MCompare *mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); const LAllocation *rhs = lir->rhs(); JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); // Load boxed boolean in ScratchReg. if (rhs->isConstant()) masm.moveValue(*rhs->toConstant(), ScratchReg); else masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg); // Perform the comparison. masm.cmpq(lhs.valueReg(), ScratchReg); emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); return true; }
bool CodeGeneratorX86::visitCompareBAndBranch(LCompareBAndBranch *lir) { MCompare *mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); const LAllocation *rhs = lir->rhs(); JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); if (mir->jsop() == JSOP_STRICTEQ) masm.branchTestBoolean(Assembler::NotEqual, lhs, lir->ifFalse()->lir()->label()); else masm.branchTestBoolean(Assembler::NotEqual, lhs, lir->ifTrue()->lir()->label()); if (rhs->isConstant()) masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean())); else masm.cmp32(lhs.payloadReg(), ToRegister(rhs)); emitBranch(JSOpToCondition(mir->jsop()), lir->ifTrue(), lir->ifFalse()); return true; }
void CodeGeneratorX64::visitCompareB(LCompareB *lir) { MCompare *mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareB::Lhs); const LAllocation *rhs = lir->rhs(); const Register output = ToRegister(lir->output()); MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); // Load boxed boolean in ScratchReg. if (rhs->isConstant()) masm.moveValue(*rhs->toConstant(), ScratchReg); else masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg); // Perform the comparison. masm.cmpPtr(lhs.valueReg(), ScratchReg); masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); }
bool CodeGeneratorX86::visitCompareVAndBranch(LCompareVAndBranch *lir) { MCompare *mir = lir->mir(); Assembler::Condition cond = JSOpToCondition(mir->jsop()); const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); Label *notEqual; if (cond == Assembler::Equal) notEqual = lir->ifFalse()->lir()->label(); else notEqual = lir->ifTrue()->lir()->label(); masm.cmp32(lhs.typeReg(), rhs.typeReg()); masm.j(Assembler::NotEqual, notEqual); masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); emitBranch(cond, lir->ifTrue(), lir->ifFalse()); return true; }
void CodeGeneratorX86::visitCompareBAndBranch(LCompareBAndBranch* lir) { MCompare* mir = lir->cmpMir(); const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); const LAllocation* rhs = lir->rhs(); MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); Assembler::Condition cond = masm.testBoolean(Assembler::NotEqual, lhs); jumpToBlock((mir->jsop() == JSOP_STRICTEQ) ? lir->ifFalse() : lir->ifTrue(), cond); if (rhs->isConstant()) masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean())); else masm.cmp32(lhs.payloadReg(), ToRegister(rhs)); emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); }
void CodeGeneratorMIPS::visitCompareBAndBranch(LCompareBAndBranch* lir) { MCompare* mir = lir->cmpMir(); const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); const LAllocation* rhs = lir->rhs(); MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); MBasicBlock* mirNotBoolean = (mir->jsop() == JSOP_STRICTEQ) ? lir->ifFalse() : lir->ifTrue(); branchToBlock(lhs.typeReg(), ImmType(JSVAL_TYPE_BOOLEAN), mirNotBoolean, Assembler::NotEqual); Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop()); if (rhs->isConstant()) emitBranch(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()), cond, lir->ifTrue(), lir->ifFalse()); else emitBranch(lhs.payloadReg(), ToRegister(rhs), cond, lir->ifTrue(), lir->ifFalse()); }
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 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 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; }