| Index: runtime/vm/intermediate_language_mips.cc
|
| ===================================================================
|
| --- runtime/vm/intermediate_language_mips.cc (revision 42125)
|
| +++ runtime/vm/intermediate_language_mips.cc (working copy)
|
| @@ -70,7 +70,7 @@
|
|
|
|
|
| LocationSummary* ReturnInstr::MakeLocationSummary(Isolate* isolate,
|
| - bool opt) const {
|
| + bool opt) const {
|
| const intptr_t kNumInputs = 1;
|
| const intptr_t kNumTemps = 0;
|
| LocationSummary* locs = new(isolate) LocationSummary(
|
| @@ -121,8 +121,7 @@
|
| case GT: return LE;
|
| case GE: return LT;
|
| default:
|
| - OS::Print("Error: Condition not recognized: %d\n", condition);
|
| - UNIMPLEMENTED();
|
| + UNREACHABLE();
|
| return EQ;
|
| }
|
| }
|
| @@ -278,7 +277,7 @@
|
| void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| __ TraceSimMsg("LoadLocalInstr");
|
| Register result = locs()->out(0).reg();
|
| - __ lw(result, Address(FP, local().index() * kWordSize));
|
| + __ LoadFromOffset(result, FP, local().index() * kWordSize);
|
| }
|
|
|
|
|
| @@ -296,7 +295,7 @@
|
| Register value = locs()->in(0).reg();
|
| Register result = locs()->out(0).reg();
|
| ASSERT(result == value); // Assert that register assignment is correct.
|
| - __ sw(value, Address(FP, local().index() * kWordSize));
|
| + __ StoreToOffset(value, FP, local().index() * kWordSize);
|
| }
|
|
|
|
|
| @@ -428,12 +427,13 @@
|
| bool opt) const {
|
| const intptr_t kNumInputs = 2;
|
| if (operation_cid() == kMintCid) {
|
| - const intptr_t kNumTemps = 1;
|
| + const intptr_t kNumTemps = 0;
|
| LocationSummary* locs = new(isolate) LocationSummary(
|
| isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| - locs->set_in(0, Location::RequiresFpuRegister());
|
| - locs->set_in(1, Location::RequiresFpuRegister());
|
| - locs->set_temp(0, Location::RequiresRegister());
|
| + locs->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + locs->set_in(1, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| locs->set_out(0, Location::RequiresRegister());
|
| return locs;
|
| }
|
| @@ -553,8 +553,7 @@
|
|
|
| static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler,
|
| const LocationSummary& locs,
|
| - Token::Kind kind,
|
| - BranchLabels labels) {
|
| + Token::Kind kind) {
|
| __ TraceSimMsg("EmitSmiComparisonOp");
|
| __ Comment("EmitSmiComparisonOp");
|
| Location left = locs.in(0);
|
| @@ -576,6 +575,69 @@
|
| }
|
|
|
|
|
| +static Condition TokenKindToMintCondition(Token::Kind kind) {
|
| + switch (kind) {
|
| + case Token::kEQ: return EQ;
|
| + case Token::kNE: return NE;
|
| + case Token::kLT: return LT;
|
| + case Token::kGT: return GT;
|
| + case Token::kLTE: return LE;
|
| + case Token::kGTE: return GE;
|
| + default:
|
| + UNREACHABLE();
|
| + return VS;
|
| + }
|
| +}
|
| +
|
| +
|
| +static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler,
|
| + const LocationSummary& locs,
|
| + Token::Kind kind) {
|
| + __ TraceSimMsg("EmitUnboxedMintEqualityOp");
|
| + __ Comment("EmitUnboxedMintEqualityOp");
|
| + ASSERT(Token::IsEqualityOperator(kind));
|
| + PairLocation* left_pair = locs.in(0).AsPairLocation();
|
| + Register left_lo = left_pair->At(0).reg();
|
| + Register left_hi = left_pair->At(1).reg();
|
| + PairLocation* right_pair = locs.in(1).AsPairLocation();
|
| + Register right_lo = right_pair->At(0).reg();
|
| + Register right_hi = right_pair->At(1).reg();
|
| +
|
| + __ xor_(CMPRES1, left_lo, right_lo);
|
| + __ xor_(CMPRES2, left_hi, right_hi);
|
| + __ or_(CMPRES1, CMPRES1, CMPRES2);
|
| + __ mov(CMPRES2, ZR);
|
| + return TokenKindToMintCondition(kind);
|
| +}
|
| +
|
| +
|
| +static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler,
|
| + const LocationSummary& locs,
|
| + Token::Kind kind) {
|
| + __ TraceSimMsg("EmitUnboxedMintComparisonOp");
|
| + __ Comment("EmitUnboxedMintComparisonOp");
|
| + PairLocation* left_pair = locs.in(0).AsPairLocation();
|
| + Register left_lo = left_pair->At(0).reg();
|
| + Register left_hi = left_pair->At(1).reg();
|
| + PairLocation* right_pair = locs.in(1).AsPairLocation();
|
| + Register right_lo = right_pair->At(0).reg();
|
| + Register right_hi = right_pair->At(1).reg();
|
| +
|
| + Label done;
|
| + // Compare upper halves first.
|
| + __ slt(CMPRES1, left_hi, right_hi);
|
| + __ slt(CMPRES2, right_hi, left_hi);
|
| + // If higher words aren't equal, skip comparing lower words.
|
| + __ bne(CMPRES1, CMPRES2, &done);
|
| +
|
| + __ sltu(CMPRES1, left_lo, right_lo);
|
| + __ sltu(CMPRES2, right_lo, left_lo);
|
| + __ Bind(&done);
|
| +
|
| + return TokenKindToMintCondition(kind);
|
| +}
|
| +
|
| +
|
| static Condition TokenKindToDoubleCondition(Token::Kind kind) {
|
| switch (kind) {
|
| case Token::kEQ: return EQ;
|
| @@ -637,7 +699,9 @@
|
| Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
| BranchLabels labels) {
|
| if (operation_cid() == kSmiCid) {
|
| - return EmitSmiComparisonOp(compiler, *locs(), kind(), labels);
|
| + return EmitSmiComparisonOp(compiler, *locs(), kind());
|
| + } else if (operation_cid() == kMintCid) {
|
| + return EmitUnboxedMintEqualityOp(compiler, *locs(), kind());
|
| } else {
|
| ASSERT(operation_cid() == kDoubleCid);
|
| return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels);
|
| @@ -801,13 +865,13 @@
|
| const intptr_t kNumInputs = 2;
|
| const intptr_t kNumTemps = 0;
|
| if (operation_cid() == kMintCid) {
|
| - const intptr_t kNumTemps = 2;
|
| + const intptr_t kNumTemps = 0;
|
| LocationSummary* locs = new(isolate) LocationSummary(
|
| isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| - locs->set_in(0, Location::RequiresFpuRegister());
|
| - locs->set_in(1, Location::RequiresFpuRegister());
|
| - locs->set_temp(0, Location::RequiresRegister());
|
| - locs->set_temp(1, Location::RequiresRegister());
|
| + locs->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + locs->set_in(1, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| locs->set_out(0, Location::RequiresRegister());
|
| return locs;
|
| }
|
| @@ -836,7 +900,9 @@
|
| Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
| BranchLabels labels) {
|
| if (operation_cid() == kSmiCid) {
|
| - return EmitSmiComparisonOp(compiler, *locs(), kind(), labels);
|
| + return EmitSmiComparisonOp(compiler, *locs(), kind());
|
| + } else if (operation_cid() == kMintCid) {
|
| + return EmitUnboxedMintComparisonOp(compiler, *locs(), kind());
|
| } else {
|
| ASSERT(operation_cid() == kDoubleCid);
|
| return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels);
|
| @@ -1196,13 +1262,16 @@
|
| if ((representation() == kUnboxedUint32) ||
|
| (representation() == kUnboxedInt32)) {
|
| const Register result = locs()->out(0).reg();
|
| + if ((index_scale() == 1) && index.IsRegister()) {
|
| + __ SmiUntag(index.reg());
|
| + }
|
| switch (class_id()) {
|
| case kTypedDataInt32ArrayCid:
|
| - ASSERT(representation() == kUnboxedUint32);
|
| + ASSERT(representation() == kUnboxedInt32);
|
| __ lw(result, element_address);
|
| break;
|
| case kTypedDataUint32ArrayCid:
|
| - ASSERT(representation() == kUnboxedInt32);
|
| + ASSERT(representation() == kUnboxedUint32);
|
| __ lw(result, element_address);
|
| break;
|
| default:
|
| @@ -1393,6 +1462,7 @@
|
| : __ ElementAddressForIntIndex(
|
| IsExternal(), class_id(), index_scale(),
|
| array, Smi::Cast(index.constant()).Value());
|
| + ASSERT(element_address.base() != TMP); // Allowed for load only.
|
|
|
| switch (class_id()) {
|
| case kArrayCid:
|
| @@ -1988,7 +2058,7 @@
|
| __ TraceSimMsg("LoadStaticFieldInstr");
|
| Register field = locs()->in(0).reg();
|
| Register result = locs()->out(0).reg();
|
| - __ lw(result, FieldAddress(field, Field::value_offset()));
|
| + __ LoadFromOffset(result, field, Field::value_offset() - kHeapObjectTag);
|
| }
|
|
|
|
|
| @@ -2577,10 +2647,10 @@
|
|
|
| // Restore stack and initialize the two exception variables:
|
| // exception and stack trace variables.
|
| - __ sw(kExceptionObjectReg,
|
| - Address(FP, exception_var().index() * kWordSize));
|
| - __ sw(kStackTraceObjectReg,
|
| - Address(FP, stacktrace_var().index() * kWordSize));
|
| + __ StoreToOffset(kExceptionObjectReg,
|
| + FP, exception_var().index() * kWordSize);
|
| + __ StoreToOffset(kStackTraceObjectReg,
|
| + FP, stacktrace_var().index() * kWordSize);
|
| }
|
|
|
|
|
| @@ -3156,7 +3226,12 @@
|
| LocationSummary* summary = new(isolate) LocationSummary(
|
| isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| summary->set_in(0, Location::RequiresRegister());
|
| - summary->set_out(0, Location::RequiresFpuRegister());
|
| + if (representation() == kUnboxedMint) {
|
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + } else {
|
| + summary->set_out(0, Location::RequiresFpuRegister());
|
| + }
|
| return summary;
|
| }
|
|
|
| @@ -3166,7 +3241,13 @@
|
|
|
| switch (representation()) {
|
| case kUnboxedMint: {
|
| - UNIMPLEMENTED();
|
| + PairLocation* result = locs()->out(0).AsPairLocation();
|
| + __ LoadFromOffset(result->At(0).reg(),
|
| + box,
|
| + ValueOffset() - kHeapObjectTag);
|
| + __ LoadFromOffset(result->At(1).reg(),
|
| + box,
|
| + ValueOffset() - kHeapObjectTag + kWordSize);
|
| break;
|
| }
|
|
|
| @@ -3195,7 +3276,9 @@
|
|
|
| switch (representation()) {
|
| case kUnboxedMint: {
|
| - UNIMPLEMENTED();
|
| + PairLocation* result = locs()->out(0).AsPairLocation();
|
| + __ SmiUntag(result->At(0).reg(), box);
|
| + __ sra(result->At(1).reg(), result->At(0).reg(), 31);
|
| break;
|
| }
|
|
|
| @@ -3271,10 +3354,10 @@
|
| Register out = locs()->out(0).reg();
|
| ASSERT(value != out);
|
|
|
| - Label done;
|
| __ SmiTag(out, value);
|
| if (!ValueFitsSmi()) {
|
| Register temp = locs()->temp(0).reg();
|
| + Label done;
|
| if (from_representation() == kUnboxedInt32) {
|
| __ SmiUntag(CMPRES1, out);
|
| __ BranchEqual(CMPRES1, value, &done);
|
| @@ -3308,8 +3391,63 @@
|
| }
|
|
|
|
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(BoxInt64Instr);
|
| +LocationSummary* BoxInt64Instr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate,
|
| + kNumInputs,
|
| + kNumTemps,
|
| + ValueFitsSmi() ? LocationSummary::kNoCall
|
| + : LocationSummary::kCallOnSlowPath);
|
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + if (!ValueFitsSmi()) {
|
| + summary->set_temp(0, Location::RequiresRegister());
|
| + }
|
| + summary->set_out(0, Location::RequiresRegister());
|
| + return summary;
|
| +}
|
|
|
| +
|
| +void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + if (ValueFitsSmi()) {
|
| + PairLocation* value_pair = locs()->in(0).AsPairLocation();
|
| + Register value_lo = value_pair->At(0).reg();
|
| + Register out_reg = locs()->out(0).reg();
|
| + __ SmiTag(out_reg, value_lo);
|
| + return;
|
| + }
|
| +
|
| + PairLocation* value_pair = locs()->in(0).AsPairLocation();
|
| + Register value_lo = value_pair->At(0).reg();
|
| + Register value_hi = value_pair->At(1).reg();
|
| + Register tmp = locs()->temp(0).reg();
|
| + Register out_reg = locs()->out(0).reg();
|
| +
|
| + Label not_smi, done;
|
| + __ SmiTag(out_reg, value_lo);
|
| + __ SmiUntag(tmp, out_reg);
|
| + __ bne(tmp, value_lo, ¬_smi);
|
| + __ delay_slot()->sra(tmp, out_reg, 31);
|
| + __ beq(tmp, value_hi, &done);
|
| +
|
| + __ Bind(¬_smi);
|
| + BoxAllocationSlowPath::Allocate(
|
| + compiler,
|
| + this,
|
| + compiler->mint_class(),
|
| + out_reg,
|
| + tmp);
|
| + __ StoreToOffset(value_lo, out_reg, Mint::value_offset() - kHeapObjectTag);
|
| + __ StoreToOffset(value_hi,
|
| + out_reg,
|
| + Mint::value_offset() - kHeapObjectTag + kWordSize);
|
| + __ Bind(&done);
|
| +}
|
| +
|
| +
|
| LocationSummary* UnboxInteger32Instr::MakeLocationSummary(Isolate* isolate,
|
| bool opt) const {
|
| ASSERT((representation() == kUnboxedInt32) ||
|
| @@ -4453,7 +4591,7 @@
|
| }
|
|
|
| // Load receiver into T0.
|
| - __ lw(T0, Address(SP, (instance_call()->ArgumentCount() - 1) * kWordSize));
|
| + __ LoadFromOffset(T0, SP, (instance_call()->ArgumentCount() - 1) * kWordSize);
|
|
|
| Label* deopt = compiler->AddDeoptStub(
|
| deopt_id(), ICData::kDeoptPolymorphicInstanceCallTestFail);
|
| @@ -4657,16 +4795,301 @@
|
| }
|
| }
|
|
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(BinaryMintOpInstr);
|
| +LocationSummary* BinaryMintOpInstr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + summary->set_in(1, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + return summary;
|
| +}
|
|
|
| +
|
| +void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + PairLocation* left_pair = locs()->in(0).AsPairLocation();
|
| + Register left_lo = left_pair->At(0).reg();
|
| + Register left_hi = left_pair->At(1).reg();
|
| + PairLocation* right_pair = locs()->in(1).AsPairLocation();
|
| + Register right_lo = right_pair->At(0).reg();
|
| + Register right_hi = right_pair->At(1).reg();
|
| + PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
| + Register out_lo = out_pair->At(0).reg();
|
| + Register out_hi = out_pair->At(1).reg();
|
| +
|
| + Label* deopt = NULL;
|
| + if (CanDeoptimize()) {
|
| + deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp);
|
| + }
|
| + switch (op_kind()) {
|
| + case Token::kBIT_AND: {
|
| + __ and_(out_lo, left_lo, right_lo);
|
| + __ and_(out_hi, left_hi, right_hi);
|
| + break;
|
| + }
|
| + case Token::kBIT_OR: {
|
| + __ or_(out_lo, left_lo, right_lo);
|
| + __ or_(out_hi, left_hi, right_hi);
|
| + break;
|
| + }
|
| + case Token::kBIT_XOR: {
|
| + __ xor_(out_lo, left_lo, right_lo);
|
| + __ xor_(out_hi, left_hi, right_hi);
|
| + break;
|
| + }
|
| + case Token::kADD:
|
| + case Token::kSUB: {
|
| + if (op_kind() == Token::kADD) {
|
| + __ addu(out_lo, left_lo, right_lo);
|
| + __ sltu(TMP, out_lo, left_lo); // TMP = carry of left_lo + right_lo.
|
| + __ addu(out_hi, left_hi, right_hi);
|
| + __ addu(out_hi, out_hi, TMP);
|
| + if (can_overflow()) {
|
| + __ xor_(CMPRES1, out_hi, left_hi);
|
| + __ xor_(TMP, out_hi, right_hi);
|
| + __ and_(CMPRES1, TMP, CMPRES1);
|
| + __ bltz(CMPRES1, deopt);
|
| + }
|
| + } else {
|
| + __ subu(out_lo, left_lo, right_lo);
|
| + __ sltu(TMP, left_lo, out_lo); // TMP = borrow of left_lo - right_lo.
|
| + __ subu(out_hi, left_hi, right_hi);
|
| + __ subu(out_hi, out_hi, TMP);
|
| + if (can_overflow()) {
|
| + __ xor_(CMPRES1, out_hi, left_hi);
|
| + __ xor_(TMP, left_hi, right_hi);
|
| + __ and_(CMPRES1, TMP, CMPRES1);
|
| + __ bltz(CMPRES1, deopt);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + case Token::kMUL: {
|
| + // The product of two signed 32-bit integers fits in a signed 64-bit
|
| + // result without causing overflow.
|
| + // We deopt on larger inputs.
|
| + // TODO(regis): Range analysis may eliminate the deopt check.
|
| + __ sra(CMPRES1, left_lo, 31);
|
| + __ bne(CMPRES1, left_hi, deopt);
|
| + __ delay_slot()->sra(CMPRES2, right_lo, 31);
|
| + __ bne(CMPRES2, right_hi, deopt);
|
| + __ delay_slot()->mult(left_lo, right_lo);
|
| + __ mflo(out_lo);
|
| + __ mfhi(out_hi);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +LocationSummary* ShiftMintOpInstr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + summary->set_in(1, Location::WritableRegisterOrSmiConstant(right()));
|
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + return summary;
|
| +}
|
| +
|
| +
|
| +static const intptr_t kMintShiftCountLimit = 63;
|
| +
|
| bool ShiftMintOpInstr::has_shift_count_check() const {
|
| - UNREACHABLE();
|
| - return false;
|
| + return !RangeUtils::IsWithin(
|
| + right()->definition()->range(), 0, kMintShiftCountLimit);
|
| }
|
|
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(ShiftMintOpInstr);
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(UnaryMintOpInstr);
|
|
|
| +void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + PairLocation* left_pair = locs()->in(0).AsPairLocation();
|
| + Register left_lo = left_pair->At(0).reg();
|
| + Register left_hi = left_pair->At(1).reg();
|
| + PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
| + Register out_lo = out_pair->At(0).reg();
|
| + Register out_hi = out_pair->At(1).reg();
|
| +
|
| + Label* deopt = NULL;
|
| + if (CanDeoptimize()) {
|
| + deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp);
|
| + }
|
| + if (locs()->in(1).IsConstant()) {
|
| + // Code for a constant shift amount.
|
| + ASSERT(locs()->in(1).constant().IsSmi());
|
| + const int32_t shift =
|
| + reinterpret_cast<int32_t>(locs()->in(1).constant().raw()) >> 1;
|
| + switch (op_kind()) {
|
| + case Token::kSHR: {
|
| + if (shift < 32) {
|
| + __ sll(out_lo, left_hi, 32 - shift);
|
| + __ srl(TMP, left_lo, shift);
|
| + __ or_(out_lo, out_lo, TMP);
|
| + __ sra(out_hi, left_hi, shift);
|
| + } else {
|
| + __ sra(out_lo, left_hi, shift - 32);
|
| + __ sra(out_hi, left_hi, 31);
|
| + }
|
| + break;
|
| + }
|
| + case Token::kSHL: {
|
| + if (shift < 32) {
|
| + __ srl(out_hi, left_lo, 32 - shift);
|
| + __ sll(TMP, left_hi, shift);
|
| + __ or_(out_hi, out_hi, TMP);
|
| + __ sll(out_lo, left_lo, shift);
|
| + } else {
|
| + __ sll(out_hi, left_lo, shift - 32);
|
| + __ mov(out_lo, ZR);
|
| + }
|
| + // Check for overflow.
|
| + if (can_overflow()) {
|
| + // Compare high word from input with shifted high word from output.
|
| + // Overflow if they aren't equal.
|
| + // If shift > 32, also compare low word from input with high word from
|
| + // output shifted back shift - 32.
|
| + if (shift > 32) {
|
| + __ sra(TMP, out_hi, shift - 32);
|
| + __ bne(left_lo, TMP, deopt);
|
| + __ delay_slot()->sra(TMP, out_hi, 31);
|
| + } else if (shift == 32) {
|
| + __ sra(TMP, out_hi, 31);
|
| + } else {
|
| + __ sra(TMP, out_hi, shift);
|
| + }
|
| + __ bne(left_hi, TMP, deopt);
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + } else {
|
| + // Code for a variable shift amount.
|
| + Register shift = locs()->in(1).reg();
|
| +
|
| + // Deopt if shift is larger than 63 or less than 0.
|
| + if (has_shift_count_check()) {
|
| + __ sltiu(CMPRES1, shift, Immediate(2*(kMintShiftCountLimit + 1)));
|
| + __ beq(CMPRES1, ZR, deopt);
|
| + // Untag shift count.
|
| + __ delay_slot()->SmiUntag(shift);
|
| + } else {
|
| + // Untag shift count.
|
| + __ SmiUntag(shift);
|
| + }
|
| +
|
| + switch (op_kind()) {
|
| + case Token::kSHR: {
|
| + Label large_shift, done;
|
| + __ sltiu(CMPRES1, shift, Immediate(32));
|
| + __ beq(CMPRES1, ZR, &large_shift);
|
| +
|
| + // shift < 32.
|
| + __ delay_slot()->ori(TMP, ZR, Immediate(32));
|
| + __ subu(TMP, TMP, shift); // TMP = 32 - shift; 0 < TMP <= 31.
|
| + __ sllv(out_lo, left_hi, TMP);
|
| + __ srlv(TMP, left_lo, shift);
|
| + __ or_(out_lo, out_lo, TMP);
|
| + __ b(&done);
|
| + __ delay_slot()->srav(out_hi, left_hi, shift);
|
| +
|
| + // shift >= 32.
|
| + __ Bind(&large_shift);
|
| + __ sra(out_hi, left_hi, 31);
|
| + __ srav(out_lo, left_hi, shift); // Only 5 low bits of shift used.
|
| +
|
| + __ Bind(&done);
|
| + break;
|
| + }
|
| + case Token::kSHL: {
|
| + Label large_shift, done;
|
| + __ sltiu(CMPRES1, shift, Immediate(32));
|
| + __ beq(CMPRES1, ZR, &large_shift);
|
| +
|
| + // shift < 32.
|
| + __ delay_slot()->ori(TMP, ZR, Immediate(32));
|
| + __ subu(TMP, TMP, shift); // TMP = 32 - shift; 0 < TMP <= 31.
|
| + __ srlv(out_hi, left_lo, TMP);
|
| + __ sllv(TMP, left_hi, shift);
|
| + __ or_(out_hi, out_hi, TMP);
|
| + // Check for overflow.
|
| + if (can_overflow()) {
|
| + // Compare high word from input with shifted high word from output.
|
| + __ srav(TMP, out_hi, shift);
|
| + __ beq(TMP, left_hi, &done);
|
| + __ delay_slot()->sllv(out_lo, left_lo, shift);
|
| + __ b(deopt);
|
| + } else {
|
| + __ b(&done);
|
| + __ delay_slot()->sllv(out_lo, left_lo, shift);
|
| + }
|
| +
|
| + // shift >= 32.
|
| + __ Bind(&large_shift);
|
| + __ sllv(out_hi, left_lo, shift); // Only 5 low bits of shift used.
|
| + // Check for overflow.
|
| + if (can_overflow()) {
|
| + // Compare low word from input with shifted high word from output and
|
| + // high word from input to sign of output.
|
| + // Overflow if they aren't equal.
|
| + __ srav(TMP, out_hi, shift);
|
| + __ bne(TMP, left_lo, deopt);
|
| + __ delay_slot()->sra(TMP, out_hi, 31);
|
| + __ bne(TMP, left_hi, deopt);
|
| + __ delay_slot()->mov(out_lo, ZR);
|
| + } else {
|
| + __ mov(out_lo, ZR);
|
| + }
|
| + __ Bind(&done);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +LocationSummary* UnaryMintOpInstr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + return summary;
|
| +}
|
| +
|
| +
|
| +void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + ASSERT(op_kind() == Token::kBIT_NOT);
|
| + PairLocation* left_pair = locs()->in(0).AsPairLocation();
|
| + Register left_lo = left_pair->At(0).reg();
|
| + Register left_hi = left_pair->At(1).reg();
|
| +
|
| + PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
| + Register out_lo = out_pair->At(0).reg();
|
| + Register out_hi = out_pair->At(1).reg();
|
| +
|
| + __ nor(out_lo, ZR, left_lo);
|
| + __ nor(out_hi, ZR, left_hi);
|
| +}
|
| +
|
| +
|
| CompileType BinaryUint32OpInstr::ComputeType() const {
|
| return CompileType::Int();
|
| }
|
| @@ -4682,9 +5105,142 @@
|
| }
|
|
|
|
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(BinaryUint32OpInstr)
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(ShiftUint32OpInstr)
|
| -DEFINE_UNIMPLEMENTED_INSTRUCTION(UnaryUint32OpInstr)
|
| +LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_in(1, Location::RequiresRegister());
|
| + summary->set_out(0, Location::RequiresRegister());
|
| + return summary;
|
| +}
|
| +
|
| +
|
| +void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + Register left = locs()->in(0).reg();
|
| + Register right = locs()->in(1).reg();
|
| + Register out = locs()->out(0).reg();
|
| + ASSERT(out != left);
|
| + switch (op_kind()) {
|
| + case Token::kBIT_AND:
|
| + __ and_(out, left, right);
|
| + break;
|
| + case Token::kBIT_OR:
|
| + __ or_(out, left, right);
|
| + break;
|
| + case Token::kBIT_XOR:
|
| + __ xor_(out, left, right);
|
| + break;
|
| + case Token::kADD:
|
| + __ addu(out, left, right);
|
| + break;
|
| + case Token::kSUB:
|
| + __ subu(out, left, right);
|
| + break;
|
| + case Token::kMUL:
|
| + __ multu(left, right);
|
| + __ mflo(out);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 1;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_in(1, Location::RegisterOrSmiConstant(right()));
|
| + summary->set_temp(0, Location::RequiresRegister());
|
| + summary->set_out(0, Location::RequiresRegister());
|
| + return summary;
|
| +}
|
| +
|
| +
|
| +void ShiftUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + const intptr_t kShifterLimit = 31;
|
| +
|
| + Register left = locs()->in(0).reg();
|
| + Register out = locs()->out(0).reg();
|
| + Register temp = locs()->temp(0).reg();
|
| +
|
| + ASSERT(left != out);
|
| +
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp);
|
| +
|
| + if (locs()->in(1).IsConstant()) {
|
| + // Shifter is constant.
|
| +
|
| + const Object& constant = locs()->in(1).constant();
|
| + ASSERT(constant.IsSmi());
|
| + const intptr_t shift_value = Smi::Cast(constant).Value();
|
| +
|
| + // Do the shift: (shift_value > 0) && (shift_value <= kShifterLimit).
|
| + switch (op_kind()) {
|
| + case Token::kSHR:
|
| + __ srl(out, left, shift_value);
|
| + break;
|
| + case Token::kSHL:
|
| + __ sll(out, left, shift_value);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + return;
|
| + }
|
| +
|
| + // Non constant shift value.
|
| + Register shifter = locs()->in(1).reg();
|
| +
|
| + __ SmiUntag(temp, shifter);
|
| + // If shift value is < 0, deoptimize.
|
| + __ bltz(temp, deopt);
|
| + __ delay_slot()->mov(out, left);
|
| + __ sltiu(CMPRES1, temp, Immediate(kShifterLimit + 1));
|
| + __ movz(out, ZR, CMPRES1); // out = shift > kShifterLimit ? 0 : left.
|
| + // Do the shift % 32.
|
| + switch (op_kind()) {
|
| + case Token::kSHR:
|
| + __ srlv(out, out, temp);
|
| + break;
|
| + case Token::kSHL:
|
| + __ sllv(out, out, temp);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +LocationSummary* UnaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
|
| + bool opt) const {
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary = new(isolate) LocationSummary(
|
| + isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_out(0, Location::RequiresRegister());
|
| + return summary;
|
| +}
|
| +
|
| +
|
| +void UnaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + Register left = locs()->in(0).reg();
|
| + Register out = locs()->out(0).reg();
|
| + ASSERT(left != out);
|
| +
|
| + ASSERT(op_kind() == Token::kBIT_NOT);
|
| +
|
| + __ nor(out, ZR, left);
|
| +}
|
| +
|
| +
|
| DEFINE_UNIMPLEMENTED_INSTRUCTION(BinaryInt32OpInstr)
|
|
|
|
|
| @@ -4695,9 +5251,15 @@
|
| LocationSummary* summary = new(isolate) LocationSummary(
|
| isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| if (from() == kUnboxedMint) {
|
| - UNREACHABLE();
|
| + ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32));
|
| + summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| + summary->set_out(0, Location::RequiresRegister());
|
| } else if (to() == kUnboxedMint) {
|
| - UNREACHABLE();
|
| + ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32));
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_out(0, Location::Pair(Location::RequiresRegister(),
|
| + Location::RequiresRegister()));
|
| } else {
|
| ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32));
|
| ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32));
|
| @@ -4723,10 +5285,34 @@
|
| __ BranchSignedLess(out, Immediate(0), deopt);
|
| }
|
| } else if (from() == kUnboxedMint) {
|
| - UNREACHABLE();
|
| - } else if (to() == kUnboxedMint) {
|
| - ASSERT(from() == kUnboxedUint32 || from() == kUnboxedInt32);
|
| - UNREACHABLE();
|
| + ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
|
| + PairLocation* in_pair = locs()->in(0).AsPairLocation();
|
| + Register in_lo = in_pair->At(0).reg();
|
| + Register in_hi = in_pair->At(1).reg();
|
| + Register out = locs()->out(0).reg();
|
| + // Copy low word.
|
| + __ mov(out, in_lo);
|
| + if (CanDeoptimize()) {
|
| + Label* deopt =
|
| + compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
|
| + ASSERT(to() == kUnboxedInt32);
|
| + __ sra(TMP, in_lo, 31);
|
| + __ bne(in_hi, TMP, deopt);
|
| + }
|
| + } else if (from() == kUnboxedUint32 || from() == kUnboxedInt32) {
|
| + ASSERT(to() == kUnboxedMint);
|
| + Register in = locs()->in(0).reg();
|
| + PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
| + Register out_lo = out_pair->At(0).reg();
|
| + Register out_hi = out_pair->At(1).reg();
|
| + // Copy low word.
|
| + __ mov(out_lo, in);
|
| + if (from() == kUnboxedUint32) {
|
| + __ xor_(out_hi, out_hi, out_hi);
|
| + } else {
|
| + ASSERT(from() == kUnboxedInt32);
|
| + __ sra(out_hi, in, 31);
|
| + }
|
| } else {
|
| UNREACHABLE();
|
| }
|
|
|