void 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()); MOZ_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->compareType(), mir->jsop()), output); masm.jump(&done); } masm.bind(¬Boolean); { masm.move32(Imm32(mir->jsop() == JSOP_STRICTNE), output); } masm.bind(&done); }
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); }
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); }
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()); }
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 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 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()); }
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::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 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()); }
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::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; }
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; }
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 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; }
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; }