| Index: src/arm/lithium-codegen-arm.cc
|
| diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
|
| index 7f5900df0e5b6de3c3071b2416dd67a77597eea0..2a1525810ee8eb14801d27301f96dde9cbc5dd15 100644
|
| --- a/src/arm/lithium-codegen-arm.cc
|
| +++ b/src/arm/lithium-codegen-arm.cc
|
| @@ -147,11 +147,11 @@ bool LCodeGen::GeneratePrologue() {
|
| // fp: Caller's frame pointer.
|
| // lr: Caller's pc.
|
|
|
| - // Classic mode functions and builtins need to replace the receiver with the
|
| + // Sloppy mode functions and builtins need to replace the receiver with the
|
| // global proxy when called as functions (without an explicit receiver
|
| // object).
|
| if (info_->this_has_uses() &&
|
| - info_->is_classic_mode() &&
|
| + info_->strict_mode() == SLOPPY &&
|
| !info_->is_native()) {
|
| Label ok;
|
| int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
| @@ -173,7 +173,6 @@ bool LCodeGen::GeneratePrologue() {
|
| __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
|
| frame_is_built_ = true;
|
| info_->AddNoFrameRange(0, masm_->pc_offset());
|
| - __ LoadConstantPoolPointerRegister();
|
| }
|
|
|
| // Reserve space for the stack slots needed by the code.
|
| @@ -269,6 +268,13 @@ void LCodeGen::GenerateOsrPrologue() {
|
| }
|
|
|
|
|
| +void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
|
| + if (!instr->IsLazyBailout() && !instr->IsGap()) {
|
| + safepoints_.BumpLastLazySafepointIndex();
|
| + }
|
| +}
|
| +
|
| +
|
| bool LCodeGen::GenerateDeferredCode() {
|
| ASSERT(is_generating());
|
| if (deferred_.length() > 0) {
|
| @@ -427,7 +433,7 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
|
| __ Move(scratch, literal);
|
| }
|
| return scratch;
|
| - } else if (op->IsStackSlot() || op->IsArgument()) {
|
| + } else if (op->IsStackSlot()) {
|
| __ ldr(scratch, ToMemOperand(op));
|
| return scratch;
|
| }
|
| @@ -463,7 +469,7 @@ DwVfpRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
|
| } else if (r.IsTagged()) {
|
| Abort(kUnsupportedTaggedImmediate);
|
| }
|
| - } else if (op->IsStackSlot() || op->IsArgument()) {
|
| + } else if (op->IsStackSlot()) {
|
| // TODO(regis): Why is vldr not taking a MemOperand?
|
| // __ vldr(dbl_scratch, ToMemOperand(op));
|
| MemOperand mem_op = ToMemOperand(op);
|
| @@ -683,10 +689,6 @@ void LCodeGen::AddToTranslation(LEnvironment* environment,
|
| }
|
| } else if (op->IsDoubleStackSlot()) {
|
| translation->StoreDoubleStackSlot(op->index());
|
| - } else if (op->IsArgument()) {
|
| - ASSERT(is_tagged);
|
| - int src_index = GetStackSlotCount() + op->index();
|
| - translation->StoreStackSlot(src_index);
|
| } else if (op->IsRegister()) {
|
| Register reg = ToRegister(op);
|
| if (is_tagged) {
|
| @@ -1115,36 +1117,71 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoModI(LModI* instr) {
|
| +void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
|
| + Register dividend = ToRegister(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + ASSERT(dividend.is(ToRegister(instr->result())));
|
| +
|
| + // Theoretically, a variation of the branch-free code for integer division by
|
| + // a power of 2 (calculating the remainder via an additional multiplication
|
| + // (which gets simplified to an 'and') and subtraction) should be faster, and
|
| + // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
|
| + // indicate that positive dividends are heavily favored, so the branching
|
| + // version performs better.
|
| HMod* hmod = instr->hydrogen();
|
| - HValue* left = hmod->left();
|
| - HValue* right = hmod->right();
|
| - if (hmod->RightIsPowerOf2()) {
|
| - // TODO(svenpanne) We should really do the strength reduction on the
|
| - // Hydrogen level.
|
| - Register left_reg = ToRegister(instr->left());
|
| - Register result_reg = ToRegister(instr->result());
|
| + int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
|
| + Label dividend_is_not_negative, done;
|
| + if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
|
| + __ cmp(dividend, Operand::Zero());
|
| + __ b(pl, ÷nd_is_not_negative);
|
| + // Note that this is correct even for kMinInt operands.
|
| + __ rsb(dividend, dividend, Operand::Zero());
|
| + __ and_(dividend, dividend, Operand(mask));
|
| + __ rsb(dividend, dividend, Operand::Zero(), SetCC);
|
| + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + __ b(&done);
|
| + }
|
|
|
| - // Note: The code below even works when right contains kMinInt.
|
| - int32_t divisor = Abs(right->GetInteger32Constant());
|
| + __ bind(÷nd_is_not_negative);
|
| + __ and_(dividend, dividend, Operand(mask));
|
| + __ bind(&done);
|
| +}
|
|
|
| - Label left_is_not_negative, done;
|
| - if (left->CanBeNegative()) {
|
| - __ cmp(left_reg, Operand::Zero());
|
| - __ b(pl, &left_is_not_negative);
|
| - __ rsb(result_reg, left_reg, Operand::Zero());
|
| - __ and_(result_reg, result_reg, Operand(divisor - 1));
|
| - __ rsb(result_reg, result_reg, Operand::Zero(), SetCC);
|
| - if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
| - __ b(&done);
|
| - }
|
|
|
| - __ bind(&left_is_not_negative);
|
| - __ and_(result_reg, left_reg, Operand(divisor - 1));
|
| - __ bind(&done);
|
| - } else if (CpuFeatures::IsSupported(SUDIV)) {
|
| +void LCodeGen::DoModByConstI(LModByConstI* instr) {
|
| + Register dividend = ToRegister(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(!dividend.is(result));
|
| +
|
| + if (divisor == 0) {
|
| + DeoptimizeIf(al, instr->environment());
|
| + return;
|
| + }
|
| +
|
| + __ FlooringDiv(result, dividend, Abs(divisor));
|
| + __ add(result, result, Operand(dividend, LSR, 31));
|
| + __ mov(ip, Operand(Abs(divisor)));
|
| + __ smull(result, ip, result, ip);
|
| + __ sub(result, dividend, result, SetCC);
|
| +
|
| + // Check for negative zero.
|
| + HMod* hmod = instr->hydrogen();
|
| + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + Label remainder_not_zero;
|
| + __ b(ne, &remainder_not_zero);
|
| + __ cmp(dividend, Operand::Zero());
|
| + DeoptimizeIf(lt, instr->environment());
|
| + __ bind(&remainder_not_zero);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoModI(LModI* instr) {
|
| + HMod* hmod = instr->hydrogen();
|
| + if (CpuFeatures::IsSupported(SUDIV)) {
|
| CpuFeatureScope scope(masm(), SUDIV);
|
|
|
| Register left_reg = ToRegister(instr->left());
|
| @@ -1154,14 +1191,14 @@ void LCodeGen::DoModI(LModI* instr) {
|
| Label done;
|
| // Check for x % 0, sdiv might signal an exception. We have to deopt in this
|
| // case because we can't return a NaN.
|
| - if (right->CanBeZero()) {
|
| + if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
|
| __ cmp(right_reg, Operand::Zero());
|
| DeoptimizeIf(eq, instr->environment());
|
| }
|
|
|
| // Check for kMinInt % -1, sdiv will return kMinInt, which is not what we
|
| // want. We have to deopt if we care about -0, because we can't return that.
|
| - if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
|
| + if (hmod->CheckFlag(HValue::kCanOverflow)) {
|
| Label no_overflow_possible;
|
| __ cmp(left_reg, Operand(kMinInt));
|
| __ b(ne, &no_overflow_possible);
|
| @@ -1184,9 +1221,7 @@ void LCodeGen::DoModI(LModI* instr) {
|
| __ mls(result_reg, result_reg, right_reg, left_reg);
|
|
|
| // If we care about -0, test if the dividend is <0 and the result is 0.
|
| - if (left->CanBeNegative() &&
|
| - hmod->CanBeZero() &&
|
| - hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| __ cmp(result_reg, Operand::Zero());
|
| __ b(ne, &done);
|
| __ cmp(left_reg, Operand::Zero());
|
| @@ -1213,7 +1248,7 @@ void LCodeGen::DoModI(LModI* instr) {
|
| Label done;
|
| // Check for x % 0, we have to deopt in this case because we can't return a
|
| // NaN.
|
| - if (right->CanBeZero()) {
|
| + if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
|
| __ cmp(right_reg, Operand::Zero());
|
| DeoptimizeIf(eq, instr->environment());
|
| }
|
| @@ -1242,9 +1277,7 @@ void LCodeGen::DoModI(LModI* instr) {
|
| __ sub(result_reg, left_reg, scratch, SetCC);
|
|
|
| // If we care about -0, test if the dividend is <0 and the result is 0.
|
| - if (left->CanBeNegative() &&
|
| - hmod->CanBeZero() &&
|
| - hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| __ b(ne, &done);
|
| __ cmp(left_reg, Operand::Zero());
|
| DeoptimizeIf(mi, instr->environment());
|
| @@ -1254,156 +1287,95 @@ void LCodeGen::DoModI(LModI* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::EmitSignedIntegerDivisionByConstant(
|
| - Register result,
|
| - Register dividend,
|
| - int32_t divisor,
|
| - Register remainder,
|
| - Register scratch,
|
| - LEnvironment* environment) {
|
| - ASSERT(!AreAliased(dividend, scratch, ip));
|
| - ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
|
| +void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
|
| + Register dividend = ToRegister(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
|
| + ASSERT(!result.is(dividend));
|
|
|
| - uint32_t divisor_abs = abs(divisor);
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + HDiv* hdiv = instr->hydrogen();
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
|
| + __ cmp(dividend, Operand::Zero());
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + // Check for (kMinInt / -1).
|
| + if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
|
| + __ cmp(dividend, Operand(kMinInt));
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + // Deoptimize if remainder will not be 0.
|
| + if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
|
| + divisor != 1 && divisor != -1) {
|
| + int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
|
| + __ tst(dividend, Operand(mask));
|
| + DeoptimizeIf(ne, instr->environment());
|
| + }
|
|
|
| - int32_t power_of_2_factor =
|
| - CompilerIntrinsics::CountTrailingZeros(divisor_abs);
|
| + if (divisor == -1) { // Nice shortcut, not needed for correctness.
|
| + __ rsb(result, dividend, Operand(0));
|
| + return;
|
| + }
|
| + int32_t shift = WhichPowerOf2Abs(divisor);
|
| + if (shift == 0) {
|
| + __ mov(result, dividend);
|
| + } else if (shift == 1) {
|
| + __ add(result, dividend, Operand(dividend, LSR, 31));
|
| + } else {
|
| + __ mov(result, Operand(dividend, ASR, 31));
|
| + __ add(result, dividend, Operand(result, LSR, 32 - shift));
|
| + }
|
| + if (shift > 0) __ mov(result, Operand(result, ASR, shift));
|
| + if (divisor < 0) __ rsb(result, result, Operand(0));
|
| +}
|
|
|
| - switch (divisor_abs) {
|
| - case 0:
|
| - DeoptimizeIf(al, environment);
|
| - return;
|
|
|
| - case 1:
|
| - if (divisor > 0) {
|
| - __ Move(result, dividend);
|
| - } else {
|
| - __ rsb(result, dividend, Operand::Zero(), SetCC);
|
| - DeoptimizeIf(vs, environment);
|
| - }
|
| - // Compute the remainder.
|
| - __ mov(remainder, Operand::Zero());
|
| - return;
|
| +void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
|
| + Register dividend = ToRegister(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(!dividend.is(result));
|
|
|
| - default:
|
| - if (IsPowerOf2(divisor_abs)) {
|
| - // Branch and condition free code for integer division by a power
|
| - // of two.
|
| - int32_t power = WhichPowerOf2(divisor_abs);
|
| - if (power > 1) {
|
| - __ mov(scratch, Operand(dividend, ASR, power - 1));
|
| - }
|
| - __ add(scratch, dividend, Operand(scratch, LSR, 32 - power));
|
| - __ mov(result, Operand(scratch, ASR, power));
|
| - // Negate if necessary.
|
| - // We don't need to check for overflow because the case '-1' is
|
| - // handled separately.
|
| - if (divisor < 0) {
|
| - ASSERT(divisor != -1);
|
| - __ rsb(result, result, Operand::Zero());
|
| - }
|
| - // Compute the remainder.
|
| - if (divisor > 0) {
|
| - __ sub(remainder, dividend, Operand(result, LSL, power));
|
| - } else {
|
| - __ add(remainder, dividend, Operand(result, LSL, power));
|
| - }
|
| - return;
|
| - } else {
|
| - // Use magic numbers for a few specific divisors.
|
| - // Details and proofs can be found in:
|
| - // - Hacker's Delight, Henry S. Warren, Jr.
|
| - // - The PowerPC Compiler Writer’s Guide
|
| - // and probably many others.
|
| - //
|
| - // We handle
|
| - // <divisor with magic numbers> * <power of 2>
|
| - // but not
|
| - // <divisor with magic numbers> * <other divisor with magic numbers>
|
| - DivMagicNumbers magic_numbers =
|
| - DivMagicNumberFor(divisor_abs >> power_of_2_factor);
|
| - // Branch and condition free code for integer division by a power
|
| - // of two.
|
| - const int32_t M = magic_numbers.M;
|
| - const int32_t s = magic_numbers.s + power_of_2_factor;
|
| -
|
| - __ mov(ip, Operand(M));
|
| - __ smull(ip, scratch, dividend, ip);
|
| - if (M < 0) {
|
| - __ add(scratch, scratch, Operand(dividend));
|
| - }
|
| - if (s > 0) {
|
| - __ mov(scratch, Operand(scratch, ASR, s));
|
| - }
|
| - __ add(result, scratch, Operand(dividend, LSR, 31));
|
| - if (divisor < 0) __ rsb(result, result, Operand::Zero());
|
| - // Compute the remainder.
|
| - __ mov(ip, Operand(divisor));
|
| - // This sequence could be replaced with 'mls' when
|
| - // it gets implemented.
|
| - __ mul(scratch, result, ip);
|
| - __ sub(remainder, dividend, scratch);
|
| - }
|
| + if (divisor == 0) {
|
| + DeoptimizeIf(al, instr->environment());
|
| + return;
|
| }
|
| -}
|
|
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + HDiv* hdiv = instr->hydrogen();
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
|
| + __ cmp(dividend, Operand::Zero());
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
|
|
| -void LCodeGen::DoDivI(LDivI* instr) {
|
| - if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
|
| - Register dividend = ToRegister(instr->left());
|
| - HDiv* hdiv = instr->hydrogen();
|
| - int32_t divisor = hdiv->right()->GetInteger32Constant();
|
| - Register result = ToRegister(instr->result());
|
| - ASSERT(!result.is(dividend));
|
| + __ FlooringDiv(result, dividend, Abs(divisor));
|
| + __ add(result, result, Operand(dividend, LSR, 31));
|
| + if (divisor < 0) __ rsb(result, result, Operand::Zero());
|
|
|
| - // Check for (0 / -x) that will produce negative zero.
|
| - if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
|
| - hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - __ cmp(dividend, Operand::Zero());
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
| - // Check for (kMinInt / -1).
|
| - if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
|
| - hdiv->CheckFlag(HValue::kCanOverflow)) {
|
| - __ cmp(dividend, Operand(kMinInt));
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
| - // Deoptimize if remainder will not be 0.
|
| - if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
|
| - Abs(divisor) != 1) {
|
| - __ tst(dividend, Operand(Abs(divisor) - 1));
|
| - DeoptimizeIf(ne, instr->environment());
|
| - }
|
| - if (divisor == -1) { // Nice shortcut, not needed for correctness.
|
| - __ rsb(result, dividend, Operand(0));
|
| - return;
|
| - }
|
| - int32_t shift = WhichPowerOf2(Abs(divisor));
|
| - if (shift == 0) {
|
| - __ mov(result, dividend);
|
| - } else if (shift == 1) {
|
| - __ add(result, dividend, Operand(dividend, LSR, 31));
|
| - } else {
|
| - __ mov(result, Operand(dividend, ASR, 31));
|
| - __ add(result, dividend, Operand(result, LSR, 32 - shift));
|
| - }
|
| - if (shift > 0) __ mov(result, Operand(result, ASR, shift));
|
| - if (divisor < 0) __ rsb(result, result, Operand(0));
|
| - return;
|
| + if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
|
| + __ mov(ip, Operand(divisor));
|
| + __ smull(scratch0(), ip, result, ip);
|
| + __ sub(scratch0(), scratch0(), dividend, SetCC);
|
| + DeoptimizeIf(ne, instr->environment());
|
| }
|
| +}
|
|
|
| - const Register left = ToRegister(instr->left());
|
| - const Register right = ToRegister(instr->right());
|
| - const Register result = ToRegister(instr->result());
|
| +
|
| +void LCodeGen::DoDivI(LDivI* instr) {
|
| + HBinaryOperation* hdiv = instr->hydrogen();
|
| + Register left = ToRegister(instr->left());
|
| + Register right = ToRegister(instr->right());
|
| + Register result = ToRegister(instr->result());
|
|
|
| // Check for x / 0.
|
| - if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
|
| + if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
|
| __ cmp(right, Operand::Zero());
|
| DeoptimizeIf(eq, instr->environment());
|
| }
|
|
|
| // Check for (0 / -x) that will produce negative zero.
|
| - if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| Label positive;
|
| if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
|
| // Do the test only if it hadn't be done above.
|
| @@ -1416,10 +1388,9 @@ void LCodeGen::DoDivI(LDivI* instr) {
|
| }
|
|
|
| // Check for (kMinInt / -1).
|
| - if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow) &&
|
| + if (hdiv->CheckFlag(HValue::kCanOverflow) &&
|
| (!CpuFeatures::IsSupported(SUDIV) ||
|
| - !instr->hydrogen_value()->CheckFlag(
|
| - HValue::kAllUsesTruncatingToInt32))) {
|
| + !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
|
| // We don't need to check for overflow when truncating with sdiv
|
| // support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
|
| __ cmp(left, Operand(kMinInt));
|
| @@ -1430,18 +1401,9 @@ void LCodeGen::DoDivI(LDivI* instr) {
|
| if (CpuFeatures::IsSupported(SUDIV)) {
|
| CpuFeatureScope scope(masm(), SUDIV);
|
| __ sdiv(result, left, right);
|
| -
|
| - if (!instr->hydrogen_value()->CheckFlag(
|
| - HInstruction::kAllUsesTruncatingToInt32)) {
|
| - // Compute remainder and deopt if it's not zero.
|
| - const Register remainder = scratch0();
|
| - __ mls(remainder, result, right, left);
|
| - __ cmp(remainder, Operand::Zero());
|
| - DeoptimizeIf(ne, instr->environment());
|
| - }
|
| } else {
|
| - const DoubleRegister vleft = ToDoubleRegister(instr->temp());
|
| - const DoubleRegister vright = double_scratch0();
|
| + DoubleRegister vleft = ToDoubleRegister(instr->temp());
|
| + DoubleRegister vright = double_scratch0();
|
| __ vmov(double_scratch0().low(), left);
|
| __ vcvt_f64_s32(vleft, double_scratch0().low());
|
| __ vmov(double_scratch0().low(), right);
|
| @@ -1449,15 +1411,23 @@ void LCodeGen::DoDivI(LDivI* instr) {
|
| __ vdiv(vleft, vleft, vright); // vleft now contains the result.
|
| __ vcvt_s32_f64(double_scratch0().low(), vleft);
|
| __ vmov(result, double_scratch0().low());
|
| + }
|
|
|
| - if (!instr->hydrogen_value()->CheckFlag(
|
| - HInstruction::kAllUsesTruncatingToInt32)) {
|
| - // Deopt if exact conversion to integer was not possible.
|
| - // Use vright as scratch register.
|
| - __ vcvt_f64_s32(double_scratch0(), double_scratch0().low());
|
| - __ VFPCompareAndSetFlags(vleft, double_scratch0());
|
| - DeoptimizeIf(ne, instr->environment());
|
| - }
|
| + if (hdiv->IsMathFloorOfDiv()) {
|
| + Label done;
|
| + Register remainder = scratch0();
|
| + __ mls(remainder, result, right, left);
|
| + __ cmp(remainder, Operand::Zero());
|
| + __ b(eq, &done);
|
| + __ eor(remainder, remainder, Operand(right));
|
| + __ add(result, result, Operand(remainder, ASR, 31));
|
| + __ bind(&done);
|
| + } else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
|
| + // Compute remainder and deopt if it's not zero.
|
| + Register remainder = scratch0();
|
| + __ mls(remainder, result, right, left);
|
| + __ cmp(remainder, Operand::Zero());
|
| + DeoptimizeIf(ne, instr->environment());
|
| }
|
| }
|
|
|
| @@ -1486,71 +1456,60 @@ void LCodeGen::DoMultiplySubD(LMultiplySubD* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
|
| - const Register result = ToRegister(instr->result());
|
| - const Register left = ToRegister(instr->left());
|
| - const Register remainder = ToRegister(instr->temp());
|
| - const Register scratch = scratch0();
|
| -
|
| - if (!CpuFeatures::IsSupported(SUDIV)) {
|
| - // If the CPU doesn't support sdiv instruction, we only optimize when we
|
| - // have magic numbers for the divisor. The standard integer division routine
|
| - // is usually slower than transitionning to VFP.
|
| - ASSERT(instr->right()->IsConstantOperand());
|
| - int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
|
| - ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
|
| - if (divisor < 0) {
|
| - __ cmp(left, Operand::Zero());
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
| - EmitSignedIntegerDivisionByConstant(result,
|
| - left,
|
| - divisor,
|
| - remainder,
|
| - scratch,
|
| - instr->environment());
|
| - // We performed a truncating division. Correct the result if necessary.
|
| - __ cmp(remainder, Operand::Zero());
|
| - __ teq(remainder, Operand(divisor), ne);
|
| - __ sub(result, result, Operand(1), LeaveCC, mi);
|
| - } else {
|
| - CpuFeatureScope scope(masm(), SUDIV);
|
| - const Register right = ToRegister(instr->right());
|
| +void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
|
| + Register dividend = ToRegister(instr->dividend());
|
| + Register result = ToRegister(instr->result());
|
| + int32_t divisor = instr->divisor();
|
| +
|
| + // If the divisor is positive, things are easy: There can be no deopts and we
|
| + // can simply do an arithmetic right shift.
|
| + if (divisor == 1) return;
|
| + int32_t shift = WhichPowerOf2Abs(divisor);
|
| + if (divisor > 1) {
|
| + __ mov(result, Operand(dividend, ASR, shift));
|
| + return;
|
| + }
|
|
|
| - // Check for x / 0.
|
| - __ cmp(right, Operand::Zero());
|
| + // If the divisor is negative, we have to negate and handle edge cases.
|
| + __ rsb(result, dividend, Operand::Zero(), SetCC);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| DeoptimizeIf(eq, instr->environment());
|
| -
|
| - // Check for (kMinInt / -1).
|
| - if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
| - __ cmp(left, Operand(kMinInt));
|
| - __ cmp(right, Operand(-1), eq);
|
| - DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
|
| + // Note that we could emit branch-free code, but that would need one more
|
| + // register.
|
| + if (divisor == -1) {
|
| + DeoptimizeIf(vs, instr->environment());
|
| + __ mov(result, Operand(dividend, ASR, shift));
|
| + } else {
|
| + __ mov(result, Operand(kMinInt / divisor), LeaveCC, vs);
|
| + __ mov(result, Operand(dividend, ASR, shift), LeaveCC, vc);
|
| }
|
| + } else {
|
| + __ mov(result, Operand(dividend, ASR, shift));
|
| + }
|
| +}
|
|
|
| - // Check for (0 / -x) that will produce negative zero.
|
| - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - __ cmp(right, Operand::Zero());
|
| - __ cmp(left, Operand::Zero(), mi);
|
| - // "right" can't be null because the code would have already been
|
| - // deoptimized. The Z flag is set only if (right < 0) and (left == 0).
|
| - // In this case we need to deoptimize to produce a -0.
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
|
|
| - Label done;
|
| - __ sdiv(result, left, right);
|
| - // If both operands have the same sign then we are done.
|
| - __ eor(remainder, left, Operand(right), SetCC);
|
| - __ b(pl, &done);
|
| +void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
|
| + Register dividend = ToRegister(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(!dividend.is(result));
|
|
|
| - // Check if the result needs to be corrected.
|
| - __ mls(remainder, result, right, left);
|
| - __ cmp(remainder, Operand::Zero());
|
| - __ sub(result, result, Operand(1), LeaveCC, ne);
|
| + if (divisor == 0) {
|
| + DeoptimizeIf(al, instr->environment());
|
| + return;
|
| + }
|
|
|
| - __ bind(&done);
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + HMathFloorOfDiv* hdiv = instr->hydrogen();
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
|
| + __ cmp(dividend, Operand::Zero());
|
| + DeoptimizeIf(eq, instr->environment());
|
| }
|
| +
|
| + __ FlooringDiv(result, dividend, divisor);
|
| }
|
|
|
|
|
| @@ -1669,7 +1628,7 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
| Register result = ToRegister(instr->result());
|
| Operand right(no_reg);
|
|
|
| - if (right_op->IsStackSlot() || right_op->IsArgument()) {
|
| + if (right_op->IsStackSlot()) {
|
| right = Operand(EmitLoadRegister(right_op, ip));
|
| } else {
|
| ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
|
| @@ -1792,7 +1751,7 @@ void LCodeGen::DoSubI(LSubI* instr) {
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
|
|
| - if (right->IsStackSlot() || right->IsArgument()) {
|
| + if (right->IsStackSlot()) {
|
| Register right_reg = EmitLoadRegister(right, ip);
|
| __ sub(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
| } else {
|
| @@ -1813,7 +1772,7 @@ void LCodeGen::DoRSubI(LRSubI* instr) {
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
|
|
| - if (right->IsStackSlot() || right->IsArgument()) {
|
| + if (right->IsStackSlot()) {
|
| Register right_reg = EmitLoadRegister(right, ip);
|
| __ rsb(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
| } else {
|
| @@ -1986,7 +1945,7 @@ void LCodeGen::DoAddI(LAddI* instr) {
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
|
|
| - if (right->IsStackSlot() || right->IsArgument()) {
|
| + if (right->IsStackSlot()) {
|
| Register right_reg = EmitLoadRegister(right, ip);
|
| __ add(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
| } else {
|
| @@ -2112,7 +2071,6 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
|
| // is in the correct position.
|
| Assembler::BlockConstPoolScope block_const_pool(masm());
|
| CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
|
| - __ nop(); // Signals no inlined code.
|
| }
|
|
|
|
|
| @@ -2736,9 +2694,6 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
|
| Register temp = ToRegister(instr->temp());
|
| Register result = ToRegister(instr->result());
|
|
|
| - ASSERT(object.is(r0));
|
| - ASSERT(result.is(r0));
|
| -
|
| // A Smi is not instance of anything.
|
| __ JumpIfSmi(object, &false_result);
|
|
|
| @@ -2796,9 +2751,6 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
|
|
|
| void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
|
| Label* map_check) {
|
| - Register result = ToRegister(instr->result());
|
| - ASSERT(result.is(r0));
|
| -
|
| InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
|
| flags = static_cast<InstanceofStub::Flags>(
|
| flags | InstanceofStub::kArgsInRegisters);
|
| @@ -2811,37 +2763,32 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
|
| PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| LoadContextFromDeferred(instr->context());
|
|
|
| - // Get the temp register reserved by the instruction. This needs to be r4 as
|
| - // its slot of the pushing of safepoint registers is used to communicate the
|
| - // offset to the location of the map check.
|
| - Register temp = ToRegister(instr->temp());
|
| - ASSERT(temp.is(r4));
|
| __ Move(InstanceofStub::right(), instr->function());
|
| - static const int kAdditionalDelta = 5;
|
| + static const int kAdditionalDelta = 4;
|
| // Make sure that code size is predicable, since we use specific constants
|
| // offsets in the code to find embedded values..
|
| - PredictableCodeSizeScope predictable(masm_, 6 * Assembler::kInstrSize);
|
| + PredictableCodeSizeScope predictable(masm_, 5 * Assembler::kInstrSize);
|
| int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
|
| Label before_push_delta;
|
| __ bind(&before_push_delta);
|
| __ BlockConstPoolFor(kAdditionalDelta);
|
| - __ mov(temp, Operand(delta * kPointerSize));
|
| + // r5 is used to communicate the offset to the location of the map check.
|
| + __ mov(r5, Operand(delta * kPointerSize));
|
| // The mov above can generate one or two instructions. The delta was computed
|
| // for two instructions, so we need to pad here in case of one instruction.
|
| if (masm_->InstructionsGeneratedSince(&before_push_delta) != 2) {
|
| ASSERT_EQ(1, masm_->InstructionsGeneratedSince(&before_push_delta));
|
| __ nop();
|
| }
|
| - __ StoreToSafepointRegisterSlot(temp, temp);
|
| CallCodeGeneric(stub.GetCode(isolate()),
|
| RelocInfo::CODE_TARGET,
|
| instr,
|
| RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
|
| LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
|
| safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
|
| - // Put the result value into the result register slot and
|
| + // Put the result value (r0) into the result register slot and
|
| // restore all registers.
|
| - __ StoreToSafepointRegisterSlot(result, result);
|
| + __ StoreToSafepointRegisterSlot(r0, ToRegister(instr->result()));
|
| }
|
|
|
|
|
| @@ -3219,7 +3166,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
|
| case FAST_ELEMENTS:
|
| case FAST_SMI_ELEMENTS:
|
| case DICTIONARY_ELEMENTS:
|
| - case NON_STRICT_ARGUMENTS_ELEMENTS:
|
| + case SLOPPY_ARGUMENTS_ELEMENTS:
|
| UNREACHABLE();
|
| break;
|
| }
|
| @@ -3965,8 +3912,9 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
|
|
|
| __ mov(r0, Operand(instr->arity()));
|
| // No cell in r2 for construct type feedback in optimized code
|
| - Handle<Object> undefined_value(isolate()->factory()->undefined_value());
|
| - __ mov(r2, Operand(undefined_value));
|
| + Handle<Object> megamorphic_symbol =
|
| + TypeFeedbackInfo::MegamorphicSentinel(isolate());
|
| + __ mov(r2, Operand(megamorphic_symbol));
|
| CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
|
| CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
|
| }
|
| @@ -3978,7 +3926,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
|
| ASSERT(ToRegister(instr->result()).is(r0));
|
|
|
| __ mov(r0, Operand(instr->arity()));
|
| - __ mov(r2, Operand(factory()->undefined_value()));
|
| + __ mov(r2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
|
| ElementsKind kind = instr->hydrogen()->elements_kind();
|
| AllocationSiteOverrideMode override_mode =
|
| (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
|
| @@ -4062,7 +4010,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| instr->hydrogen()->value()->IsHeapObject()
|
| ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
|
|
| - if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
| + if (representation.IsHeapObject()) {
|
| Register value = ToRegister(instr->value());
|
| if (!instr->hydrogen()->value()->type().IsHeapObject()) {
|
| __ SmiTst(value);
|
| @@ -4140,8 +4088,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
|
|
| // Name is always in r2.
|
| __ mov(r2, Operand(instr->name()));
|
| - Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
| - instr->strict_mode_flag());
|
| + Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
|
| }
|
|
|
| @@ -4262,7 +4209,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
|
| case FAST_HOLEY_ELEMENTS:
|
| case FAST_HOLEY_SMI_ELEMENTS:
|
| case DICTIONARY_ELEMENTS:
|
| - case NON_STRICT_ARGUMENTS_ELEMENTS:
|
| + case SLOPPY_ARGUMENTS_ELEMENTS:
|
| UNREACHABLE();
|
| break;
|
| }
|
| @@ -4378,7 +4325,7 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
|
| ASSERT(ToRegister(instr->key()).is(r1));
|
| ASSERT(ToRegister(instr->value()).is(r0));
|
|
|
| - Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
|
| + Handle<Code> ic = instr->strict_mode() == STRICT
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize();
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
|
| @@ -4564,20 +4511,6 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
|
| - LOperand* input = instr->value();
|
| - LOperand* output = instr->result();
|
| - ASSERT(output->IsRegister());
|
| - if (!instr->hydrogen()->value()->HasRange() ||
|
| - !instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
| - __ SmiTag(ToRegister(output), ToRegister(input), SetCC);
|
| - DeoptimizeIf(vs, instr->environment());
|
| - } else {
|
| - __ SmiTag(ToRegister(output), ToRegister(input));
|
| - }
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
| LOperand* input = instr->value();
|
| LOperand* output = instr->result();
|
| @@ -4588,27 +4521,17 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
|
| - LOperand* input = instr->value();
|
| - LOperand* output = instr->result();
|
| - if (!instr->hydrogen()->value()->HasRange() ||
|
| - !instr->hydrogen()->value()->range()->IsInSmiRange()) {
|
| - __ tst(ToRegister(input), Operand(0xc0000000));
|
| - DeoptimizeIf(ne, instr->environment());
|
| - }
|
| - __ SmiTag(ToRegister(output), ToRegister(input));
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
|
| class DeferredNumberTagI V8_FINAL : public LDeferredCode {
|
| public:
|
| DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
|
| : LDeferredCode(codegen), instr_(instr) { }
|
| virtual void Generate() V8_OVERRIDE {
|
| - codegen()->DoDeferredNumberTagI(instr_,
|
| - instr_->value(),
|
| - SIGNED_INT32);
|
| + codegen()->DoDeferredNumberTagIU(instr_,
|
| + instr_->value(),
|
| + instr_->temp1(),
|
| + instr_->temp2(),
|
| + SIGNED_INT32);
|
| }
|
| virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
|
| private:
|
| @@ -4631,9 +4554,11 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
|
| DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
|
| : LDeferredCode(codegen), instr_(instr) { }
|
| virtual void Generate() V8_OVERRIDE {
|
| - codegen()->DoDeferredNumberTagI(instr_,
|
| - instr_->value(),
|
| - UNSIGNED_INT32);
|
| + codegen()->DoDeferredNumberTagIU(instr_,
|
| + instr_->value(),
|
| + instr_->temp1(),
|
| + instr_->temp2(),
|
| + UNSIGNED_INT32);
|
| }
|
| virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
|
| private:
|
| @@ -4651,18 +4576,19 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
|
| - LOperand* value,
|
| - IntegerSignedness signedness) {
|
| - Label slow;
|
| +void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr,
|
| + LOperand* value,
|
| + LOperand* temp1,
|
| + LOperand* temp2,
|
| + IntegerSignedness signedness) {
|
| + Label done, slow;
|
| Register src = ToRegister(value);
|
| Register dst = ToRegister(instr->result());
|
| + Register tmp1 = scratch0();
|
| + Register tmp2 = ToRegister(temp1);
|
| + Register tmp3 = ToRegister(temp2);
|
| LowDwVfpRegister dbl_scratch = double_scratch0();
|
|
|
| - // Preserve the value of all registers.
|
| - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| -
|
| - Label done;
|
| if (signedness == SIGNED_INT32) {
|
| // There was overflow, so bits 30 and 31 of the original integer
|
| // disagree. Try to allocate a heap number in new space and store
|
| @@ -4679,38 +4605,40 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
|
| }
|
|
|
| if (FLAG_inline_new) {
|
| - __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
|
| - __ AllocateHeapNumber(r5, r3, r4, scratch0(), &slow, DONT_TAG_RESULT);
|
| - __ Move(dst, r5);
|
| + __ LoadRoot(tmp3, Heap::kHeapNumberMapRootIndex);
|
| + __ AllocateHeapNumber(dst, tmp1, tmp2, tmp3, &slow, DONT_TAG_RESULT);
|
| __ b(&done);
|
| }
|
|
|
| // Slow case: Call the runtime system to do the number allocation.
|
| __ bind(&slow);
|
| + {
|
| + // TODO(3095996): Put a valid pointer value in the stack slot where the
|
| + // result register is stored, as this register is in the pointer map, but
|
| + // contains an integer value.
|
| + __ mov(dst, Operand::Zero());
|
|
|
| - // TODO(3095996): Put a valid pointer value in the stack slot where the result
|
| - // register is stored, as this register is in the pointer map, but contains an
|
| - // integer value.
|
| - __ mov(ip, Operand::Zero());
|
| - __ StoreToSafepointRegisterSlot(ip, dst);
|
| - // NumberTagI and NumberTagD use the context from the frame, rather than
|
| - // the environment's HContext or HInlinedContext value.
|
| - // They only call Runtime::kAllocateHeapNumber.
|
| - // The corresponding HChange instructions are added in a phase that does
|
| - // not have easy access to the local context.
|
| - __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
| - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| - RecordSafepointWithRegisters(
|
| - instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| - __ Move(dst, r0);
|
| - __ sub(dst, dst, Operand(kHeapObjectTag));
|
| + // Preserve the value of all registers.
|
| + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| +
|
| + // NumberTagI and NumberTagD use the context from the frame, rather than
|
| + // the environment's HContext or HInlinedContext value.
|
| + // They only call Runtime::kAllocateHeapNumber.
|
| + // The corresponding HChange instructions are added in a phase that does
|
| + // not have easy access to the local context.
|
| + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
| + __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| + RecordSafepointWithRegisters(
|
| + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| + __ sub(r0, r0, Operand(kHeapObjectTag));
|
| + __ StoreToSafepointRegisterSlot(r0, dst);
|
| + }
|
|
|
| // Done. Put the value in dbl_scratch into the value of the allocated heap
|
| // number.
|
| __ bind(&done);
|
| __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset);
|
| __ add(dst, dst, Operand(kHeapObjectTag));
|
| - __ StoreToSafepointRegisterSlot(dst, dst);
|
| }
|
|
|
|
|
| @@ -4772,8 +4700,21 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
|
|
|
|
|
| void LCodeGen::DoSmiTag(LSmiTag* instr) {
|
| - ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
|
| - __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
|
| + HChange* hchange = instr->hydrogen();
|
| + Register input = ToRegister(instr->value());
|
| + Register output = ToRegister(instr->result());
|
| + if (hchange->CheckFlag(HValue::kCanOverflow) &&
|
| + hchange->value()->CheckFlag(HValue::kUint32)) {
|
| + __ tst(input, Operand(0xc0000000));
|
| + DeoptimizeIf(ne, instr->environment());
|
| + }
|
| + if (hchange->CheckFlag(HValue::kCanOverflow) &&
|
| + !hchange->value()->CheckFlag(HValue::kUint32)) {
|
| + __ SmiTag(output, input, SetCC);
|
| + DeoptimizeIf(vs, instr->environment());
|
| + } else {
|
| + __ SmiTag(output, input);
|
| + }
|
| }
|
|
|
|
|
| @@ -5223,6 +5164,26 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
|
| }
|
|
|
|
|
| +void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
|
| + DwVfpRegister value_reg = ToDoubleRegister(instr->value());
|
| + Register result_reg = ToRegister(instr->result());
|
| + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
|
| + __ VmovHigh(result_reg, value_reg);
|
| + } else {
|
| + __ VmovLow(result_reg, value_reg);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
|
| + Register hi_reg = ToRegister(instr->hi());
|
| + Register lo_reg = ToRegister(instr->lo());
|
| + DwVfpRegister result_reg = ToDoubleRegister(instr->result());
|
| + __ VmovHigh(result_reg, hi_reg);
|
| + __ VmovLow(result_reg, lo_reg);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoAllocate(LAllocate* instr) {
|
| class DeferredAllocate V8_FINAL : public LDeferredCode {
|
| public:
|
| @@ -5393,7 +5354,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
|
| // space for nested functions that don't need literals cloning.
|
| bool pretenure = instr->hydrogen()->pretenure();
|
| if (!pretenure && instr->hydrogen()->has_no_literals()) {
|
| - FastNewClosureStub stub(instr->hydrogen()->language_mode(),
|
| + FastNewClosureStub stub(instr->hydrogen()->strict_mode(),
|
| instr->hydrogen()->is_generator());
|
| __ mov(r2, Operand(instr->hydrogen()->shared_info()));
|
| CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
|
|
|