| Index: src/a64/lithium-codegen-a64.cc
|
| diff --git a/src/a64/lithium-codegen-a64.cc b/src/a64/lithium-codegen-a64.cc
|
| index 207e053522d01c92f746f6737365f9c00b57da10..c0649f1698a3db51d114dc721ff2137a88e5f1a1 100644
|
| --- a/src/a64/lithium-codegen-a64.cc
|
| +++ b/src/a64/lithium-codegen-a64.cc
|
| @@ -945,12 +945,6 @@ void LCodeGen::Deoptimize(LEnvironment* environment) {
|
| }
|
|
|
|
|
| -void LCodeGen::SoftDeoptimize(LEnvironment* environment) {
|
| - ASSERT(!info()->IsStub());
|
| - Deoptimize(environment, Deoptimizer::SOFT);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DeoptimizeIf(Condition cond, LEnvironment* environment) {
|
| Label dont_deopt;
|
| __ B(InvertCondition(cond), &dont_deopt);
|
| @@ -1070,7 +1064,10 @@ Operand LCodeGen::ToOperand(LOperand* op) {
|
| LConstantOperand* const_op = LConstantOperand::cast(op);
|
| HConstant* constant = chunk()->LookupConstant(const_op);
|
| Representation r = chunk_->LookupLiteralRepresentation(const_op);
|
| - if (r.IsInteger32()) {
|
| + if (r.IsSmi()) {
|
| + ASSERT(constant->HasSmiValue());
|
| + return Operand(Smi::FromInt(constant->Integer32Value()));
|
| + } else if (r.IsInteger32()) {
|
| ASSERT(constant->HasInteger32Value());
|
| return Operand(constant->Integer32Value());
|
| } else if (r.IsDouble()) {
|
| @@ -1300,6 +1297,20 @@ void LCodeGen::DoAddI(LAddI* instr) {
|
| }
|
|
|
|
|
| +void LCodeGen::DoAddS(LAddS* instr) {
|
| + bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| + Register result = ToRegister(instr->result());
|
| + Register left = ToRegister(instr->left());
|
| + Operand right = ToOperand(instr->right());
|
| + if (can_overflow) {
|
| + __ Adds(result, left, right);
|
| + DeoptimizeIf(vs, instr->environment());
|
| + } else {
|
| + __ Add(result, left, right);
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoAllocate(LAllocate* instr) {
|
| class DeferredAllocate: public LDeferredCode {
|
| public:
|
| @@ -1539,13 +1550,25 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
|
|
|
|
|
| void LCodeGen::DoBitI(LBitI* instr) {
|
| - LOperand* left_op = instr->left();
|
| - LOperand* right_op = instr->right();
|
| - Register left = ToRegister(left_op);
|
| - Register result = ToRegister(instr->result());
|
| + Register result = ToRegister32(instr->result());
|
| + Register left = ToRegister32(instr->left());
|
| + Operand right = ToOperand32(instr->right());
|
|
|
| - ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
|
| - Operand right = ToOperand(right_op);
|
| + switch (instr->op()) {
|
| + case Token::BIT_AND: __ And(result, left, right); break;
|
| + case Token::BIT_OR: __ Orr(result, left, right); break;
|
| + case Token::BIT_XOR: __ Eor(result, left, right); break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoBitS(LBitS* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + Register left = ToRegister(instr->left());
|
| + Operand right = ToOperand(instr->right());
|
|
|
| switch (instr->op()) {
|
| case Token::BIT_AND: __ And(result, left, right); break;
|
| @@ -1565,6 +1588,15 @@ void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
| }
|
|
|
|
|
| +void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) {
|
| + if (FLAG_debug_code && check->hydrogen()->skip_check()) {
|
| + __ Assert(InvertCondition(cc), "eliminated bounds check failed");
|
| + } else {
|
| + DeoptimizeIf(cc, check->environment());
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoBoundsCheck(LBoundsCheck *instr) {
|
| if (instr->hydrogen()->skip_check()) return;
|
|
|
| @@ -1582,7 +1614,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck *instr) {
|
| } else {
|
| __ Cmp(length, ToRegister(instr->index()));
|
| }
|
| - DeoptimizeIf(ls, instr->environment());
|
| + Condition condition = instr->hydrogen()->allow_equality() ? lo : ls;
|
| + ApplyCheckIf(condition, instr);
|
| }
|
|
|
|
|
| @@ -1901,6 +1934,11 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
|
|
|
|
| void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
|
| + if (instr->hydrogen()->CanOmitMapChecks()) {
|
| + ASSERT(instr->temp() == NULL);
|
| + return;
|
| + }
|
| +
|
| Register object = ToRegister(instr->value());
|
| Register map_reg = ToRegister(instr->temp());
|
|
|
| @@ -1931,25 +1969,28 @@ void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
|
|
|
|
|
| void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
| + if (instr->hydrogen()->CanOmitPrototypeChecks()) {
|
| + ASSERT(instr->temp1() == NULL);
|
| + ASSERT(instr->temp2() == NULL);
|
| + return;
|
| + }
|
| +
|
| ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
|
| ZoneList<Handle<Map> >* maps = instr->maps();
|
| ASSERT(prototypes->length() == maps->length());
|
|
|
| - if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
|
| - // TODO(jbramley): The temp registers are only needed in this case.
|
| - Label success, deopt;
|
| - Register temp1 = ToRegister(instr->temp1());
|
| - Register temp2 = ToRegister(instr->temp2());
|
| - for (int i = 0; i < prototypes->length(); i++) {
|
| - __ LoadHeapObject(temp1, prototypes->at(i));
|
| - __ Ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
|
| - __ CompareMap(temp2, maps->at(i), &success);
|
| - __ B(eq, &success);
|
| - }
|
| - // If we didn't match a map, deoptimize.
|
| - Deoptimize(instr->environment());
|
| - __ Bind(&success);
|
| + Label success, deopt;
|
| + Register temp1 = ToRegister(instr->temp1());
|
| + Register temp2 = ToRegister(instr->temp2());
|
| + for (int i = 0; i < prototypes->length(); i++) {
|
| + __ LoadHeapObject(temp1, prototypes->at(i));
|
| + __ Ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
|
| + __ CompareMap(temp2, maps->at(i), &success);
|
| + __ B(eq, &success);
|
| }
|
| + // If we didn't match a map, deoptimize.
|
| + Deoptimize(instr->environment());
|
| + __ Bind(&success);
|
| }
|
|
|
|
|
| @@ -2248,12 +2289,7 @@ void LCodeGen::DoConstantS(LConstantS* instr) {
|
| void LCodeGen::DoConstantT(LConstantT* instr) {
|
| Handle<Object> value = instr->value();
|
| AllowDeferredHandleDereference smi_check;
|
| - if (value->IsSmi()) {
|
| - __ Mov(ToRegister(instr->result()), Operand(value));
|
| - } else {
|
| - __ LoadHeapObject(ToRegister(instr->result()),
|
| - Handle<HeapObject>::cast(value));
|
| - }
|
| + __ LoadObject(ToRegister(instr->result()), value);
|
| }
|
|
|
|
|
| @@ -2342,11 +2378,15 @@ void LCodeGen::DoDateField(LDateField* instr) {
|
|
|
|
|
| void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
|
| - if (instr->hydrogen_value()->IsSoftDeoptimize()) {
|
| - SoftDeoptimize(instr->environment());
|
| - } else {
|
| - Deoptimize(instr->environment());
|
| + Deoptimizer::BailoutType type = instr->hydrogen()->type();
|
| + // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
|
| + // needed return address), even though the implementation of LAZY and EAGER is
|
| + // now identical. When LAZY is eventually completely folded into EAGER, remove
|
| + // the special case below.
|
| + if (info()->IsStub() && (type == Deoptimizer::EAGER)) {
|
| + type = Deoptimizer::LAZY;
|
| }
|
| + Deoptimize(instr->environment(), type);
|
| }
|
|
|
|
|
| @@ -3404,9 +3444,9 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
|
| __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
|
| __ Ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
|
| }
|
| - } else if (lookup.IsConstantFunction()) {
|
| - Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
|
| - __ LoadHeapObject(result, function);
|
| + } else if (lookup.IsConstant()) {
|
| + Handle<Object> constant(lookup.GetConstantFromMap(*type), isolate());
|
| + __ LoadObject(result, constant);
|
| } else {
|
| // Negative lookup. Check prototypes.
|
| Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
|
| @@ -3972,6 +4012,13 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
|
|
|
| __ Cmp(left, right);
|
| __ Csel(result, left, right, (op == HMathMinMax::kMathMax) ? ge : le);
|
| + } else if (instr->hydrogen()->representation().IsSmi()) {
|
| + Register result = ToRegister(instr->result());
|
| + Register left = ToRegister(instr->left());
|
| + Operand right = ToOperand(instr->right());
|
| +
|
| + __ Cmp(left, right);
|
| + __ Csel(result, left, right, (op == HMathMinMax::kMathMax) ? ge : le);
|
| } else {
|
| ASSERT(instr->hydrogen()->representation().IsDouble());
|
| DoubleRegister result = ToDoubleRegister(instr->result());
|
| @@ -4047,6 +4094,8 @@ void LCodeGen::DoModI(LModI* instr) {
|
|
|
|
|
| void LCodeGen::DoMulConstI(LMulConstI* instr) {
|
| + // TODO(jbramley): Support smi operations (or make a separate DoMulConstS).
|
| +
|
| Register result = ToRegister32(instr->result());
|
| Register left = ToRegister32(instr->left());
|
| int32_t right = ToInteger32(instr->right());
|
| @@ -4139,12 +4188,12 @@ void LCodeGen::DoMulConstI(LMulConstI* instr) {
|
| void LCodeGen::DoMulI(LMulI* instr) {
|
| Register result = ToRegister32(instr->result());
|
| Register left = ToRegister32(instr->left());
|
| + Register right = ToRegister32(instr->right());
|
|
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| bool bailout_on_minus_zero =
|
| instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
|
|
| - Register right = ToRegister32(instr->right());
|
| if (bailout_on_minus_zero) {
|
| // If one operand is zero and the other is negative, the result is -0.
|
| // - Set Z (eq) if either left or right, or both, are 0.
|
| @@ -4166,6 +4215,41 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
| }
|
|
|
|
|
| +void LCodeGen::DoMulS(LMulS* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + Register left = ToRegister(instr->left());
|
| + Register right = ToRegister(instr->right());
|
| +
|
| + bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| + bool bailout_on_minus_zero =
|
| + instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
| +
|
| + if (bailout_on_minus_zero) {
|
| + // If one operand is zero and the other is negative, the result is -0.
|
| + // - Set Z (eq) if either left or right, or both, are 0.
|
| + __ Cmp(left, 0);
|
| + __ Ccmp(right, 0, ZFlag, ne);
|
| + // - If so (eq), set N (mi) if left + right is negative.
|
| + // - Otherwise, clear N.
|
| + __ Ccmn(left, right, NoFlag, eq);
|
| + DeoptimizeIf(mi, instr->environment());
|
| + }
|
| +
|
| + STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0));
|
| + if (can_overflow) {
|
| + __ Smulh(result, left, right);
|
| + __ Cmp(result, Operand(result.W(), SXTW));
|
| + __ SmiTag(result);
|
| + DeoptimizeIf(ne, instr->environment());
|
| + } else {
|
| + // TODO(jbramley): This could be rewritten to support UseRegisterAtStart.
|
| + ASSERT(!AreAliased(result, right));
|
| + __ SmiUntag(result, left);
|
| + __ Mul(result, result, right);
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
|
| // TODO(3095996): Get rid of this. For now, we need to make the
|
| // result register contain a valid pointer because it is already
|
| @@ -5269,32 +5353,24 @@ void LCodeGen::DoThrow(LThrow* instr) {
|
|
|
| void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
|
| Register object = ToRegister(instr->object());
|
| + Register temp1 = ToRegister(instr->temp1());
|
|
|
| Handle<Map> from_map = instr->original_map();
|
| Handle<Map> to_map = instr->transitioned_map();
|
| ElementsKind from_kind = instr->from_kind();
|
| ElementsKind to_kind = instr->to_kind();
|
|
|
| - Register scratch;
|
| - if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
|
| - scratch = ToRegister(instr->temp1());
|
| - } else {
|
| - ASSERT(FLAG_compiled_transitions || instr->IsMarkedAsCall());
|
| - scratch = x10;
|
| - }
|
| -
|
| Label not_applicable;
|
| - __ CompareMap(object, scratch, from_map);
|
| - __ B(ne, ¬_applicable);
|
| + __ CheckMap(object, temp1, from_map, ¬_applicable, DONT_DO_SMI_CHECK);
|
|
|
| if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
|
| Register new_map = ToRegister(instr->temp2());
|
| __ Mov(new_map, Operand(to_map));
|
| __ Str(new_map, FieldMemOperand(object, HeapObject::kMapOffset));
|
| // Write barrier.
|
| - __ RecordWriteField(object, HeapObject::kMapOffset, new_map, scratch,
|
| + __ RecordWriteField(object, HeapObject::kMapOffset, new_map, temp1,
|
| GetLinkRegisterState(), kDontSaveFPRegs);
|
| - } else if (FLAG_compiled_transitions) {
|
| + } else {
|
| PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| __ Mov(x0, object);
|
| __ Mov(x1, Operand(to_map));
|
| @@ -5302,22 +5378,6 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
|
| __ CallStub(&stub);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
|
| - } else if ((IsFastSmiElementsKind(from_kind) &&
|
| - IsFastDoubleElementsKind(to_kind)) ||
|
| - (IsFastDoubleElementsKind(from_kind) &&
|
| - IsFastObjectElementsKind(to_kind))) {
|
| - ASSERT((instr->temp1() == NULL) && (instr->temp2() == NULL));
|
| - __ Mov(x2, object);
|
| - __ Mov(x3, Operand(to_map));
|
| - if (IsFastSmiElementsKind(from_kind)) {
|
| - CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
|
| - RelocInfo::CODE_TARGET, instr);
|
| - } else if (IsFastDoubleElementsKind(from_kind)) {
|
| - CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
|
| - RelocInfo::CODE_TARGET, instr);
|
| - }
|
| - } else {
|
| - UNREACHABLE();
|
| }
|
| __ Bind(¬_applicable);
|
| }
|
|
|