diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index 0656b4b84932..11601a189ed1 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -1208,13 +1208,22 @@ void CodeGenerator::visitDivPowTwoI(LDivPowTwoI* ins) { // rounded result when the numerator is negative. See 10-1 // "Signed Division by a Known Power of 2" in Henry // S. Warren, Jr.'s Hacker's Delight. - if (mir->canBeNegativeDividend()) { + if (mir->canBeNegativeDividend() && mir->isTruncated()) { + // Note: There is no need to execute this code, which handles how to + // round the signed integer division towards 0, if we previously bailed + // due to a non-zero remainder. Register lhsCopy = ToRegister(ins->numeratorCopy()); MOZ_ASSERT(lhsCopy != lhs); if (shift > 1) { + // Copy the sign bit of the numerator. (= (2^32 - 1) or 0) masm.sarl(Imm32(31), lhs); } + // Divide by 2^(32 - shift) + // i.e. (= (2^32 - 1) / 2^(32 - shift) or 0) + // i.e. (= (2^shift - 1) or 0) masm.shrl(Imm32(32 - shift), lhs); + // If signed, make any 1 bit below the shifted bits to bubble up, such + // that once shifted the value would be rounded towards 0. masm.addl(lhsCopy, lhs); } masm.sarl(Imm32(shift), lhs); diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.cpp b/js/src/jit/x86-shared/Lowering-x86-shared.cpp index b1742e4ff491..aac0999707f4 100644 --- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp +++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp @@ -173,12 +173,16 @@ void LIRGeneratorX86Shared::lowerDivI(MDiv* div) { if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) { LAllocation lhs = useRegisterAtStart(div->lhs()); LDivPowTwoI* lir; - if (!div->canBeNegativeDividend()) { + // When truncated with maybe a non-zero remainder, we have to round the + // result toward 0. This requires an extra register to round up/down + // whether the left-hand-side is signed. + bool needRoundNeg = div->canBeNegativeDividend() && div->isTruncated(); + if (!needRoundNeg) { // Numerator is unsigned, so does not need adjusting. lir = new (alloc()) LDivPowTwoI(lhs, lhs, shift, rhs < 0); } else { - // Numerator is signed, and needs adjusting, and an extra - // lhs copy register is needed. + // Numerator might be signed, and needs adjusting, and an extra lhs copy + // is needed to round the result of the integer division towards zero. lir = new (alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift, rhs < 0); }