| Index: src/mips64/macro-assembler-mips64.h
|
| diff --git a/src/mips/macro-assembler-mips.h b/src/mips64/macro-assembler-mips64.h
|
| similarity index 92%
|
| copy from src/mips/macro-assembler-mips.h
|
| copy to src/mips64/macro-assembler-mips64.h
|
| index 8644827f8e9b6bf4cc8f309f52add3e3d805ad8d..4c262f68e514588046caffd5055e35a8998bc278 100644
|
| --- a/src/mips/macro-assembler-mips.h
|
| +++ b/src/mips64/macro-assembler-mips64.h
|
| @@ -7,7 +7,7 @@
|
|
|
| #include "src/assembler.h"
|
| #include "src/globals.h"
|
| -#include "src/mips/assembler-mips.h"
|
| +#include "src/mips64/assembler-mips64.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -61,11 +61,17 @@ enum BranchDelaySlot {
|
| // Flags used for the li macro-assembler function.
|
| enum LiFlags {
|
| // If the constant value can be represented in just 16 bits, then
|
| - // optimize the li to use a single instruction, rather than lui/ori pair.
|
| + // optimize the li to use a single instruction, rather than lui/ori/dsll
|
| + // sequence.
|
| OPTIMIZE_SIZE = 0,
|
| - // Always use 2 instructions (lui/ori pair), even if the constant could
|
| - // be loaded with just one, so that this value is patchable later.
|
| - CONSTANT_SIZE = 1
|
| + // Always use 6 instructions (lui/ori/dsll sequence), even if the constant
|
| + // could be loaded with just one, so that this value is patchable later.
|
| + CONSTANT_SIZE = 1,
|
| + // For address loads only 4 instruction are required. Used to mark
|
| + // constant load that will be used as address without relocation
|
| + // information. It ensures predictable code size, so specific sites
|
| + // in code are patchable.
|
| + ADDRESS_LOAD = 2
|
| };
|
|
|
|
|
| @@ -106,8 +112,23 @@ inline MemOperand FieldMemOperand(Register object, int offset) {
|
| }
|
|
|
|
|
| +inline MemOperand UntagSmiMemOperand(Register rm, int offset) {
|
| + // Assumes that Smis are shifted by 32 bits and little endianness.
|
| + STATIC_ASSERT(kSmiShift == 32);
|
| + return MemOperand(rm, offset + (kSmiShift / kBitsPerByte));
|
| +}
|
| +
|
| +
|
| +inline MemOperand UntagSmiFieldMemOperand(Register rm, int offset) {
|
| + return UntagSmiMemOperand(rm, offset - kHeapObjectTag);
|
| +}
|
| +
|
| +
|
| // Generate a MemOperand for storing arguments 5..N on the stack
|
| // when calling CallCFunction().
|
| +// TODO(plind): Currently ONLY used for O32. Should be fixed for
|
| +// n64, and used in RegExp code, and other places
|
| +// with more than 8 arguments.
|
| inline MemOperand CFunctionArgumentOperand(int index) {
|
| ASSERT(index > kCArgSlotCount);
|
| // Argument 5 takes the slot just past the four Arg-slots.
|
| @@ -227,11 +248,11 @@ class MacroAssembler: public Assembler {
|
|
|
| inline void Move(Register dst_low, Register dst_high, FPURegister src) {
|
| mfc1(dst_low, src);
|
| - mfc1(dst_high, FPURegister::from_code(src.code() + 1));
|
| + mfhc1(dst_high, src);
|
| }
|
|
|
| inline void FmoveHigh(Register dst_high, FPURegister src) {
|
| - mfc1(dst_high, FPURegister::from_code(src.code() + 1));
|
| + mfhc1(dst_high, src);
|
| }
|
|
|
| inline void FmoveLow(Register dst_low, FPURegister src) {
|
| @@ -240,7 +261,7 @@ class MacroAssembler: public Assembler {
|
|
|
| inline void Move(FPURegister dst, Register src_low, Register src_high) {
|
| mtc1(src_low, dst);
|
| - mtc1(src_high, FPURegister::from_code(dst.code() + 1));
|
| + mthc1(src_high, dst);
|
| }
|
|
|
| // Conditional move.
|
| @@ -546,8 +567,7 @@ class MacroAssembler: public Assembler {
|
| Register scratch2,
|
| Register heap_number_map,
|
| Label* gc_required,
|
| - TaggingMode tagging_mode = TAG_RESULT,
|
| - MutableMode mode = IMMUTABLE);
|
| + TaggingMode tagging_mode = TAG_RESULT);
|
| void AllocateHeapNumberWithValue(Register result,
|
| FPURegister value,
|
| Register scratch1,
|
| @@ -576,12 +596,19 @@ class MacroAssembler: public Assembler {
|
| }
|
|
|
| DEFINE_INSTRUCTION(Addu);
|
| + DEFINE_INSTRUCTION(Daddu);
|
| DEFINE_INSTRUCTION(Subu);
|
| + DEFINE_INSTRUCTION(Dsubu);
|
| DEFINE_INSTRUCTION(Mul);
|
| + DEFINE_INSTRUCTION(Dmul);
|
| DEFINE_INSTRUCTION2(Mult);
|
| + DEFINE_INSTRUCTION2(Dmult);
|
| DEFINE_INSTRUCTION2(Multu);
|
| + DEFINE_INSTRUCTION2(Dmultu);
|
| DEFINE_INSTRUCTION2(Div);
|
| + DEFINE_INSTRUCTION2(Ddiv);
|
| DEFINE_INSTRUCTION2(Divu);
|
| + DEFINE_INSTRUCTION2(Ddivu);
|
|
|
| DEFINE_INSTRUCTION(And);
|
| DEFINE_INSTRUCTION(Or);
|
| @@ -594,6 +621,7 @@ class MacroAssembler: public Assembler {
|
|
|
| // MIPS32 R2 instruction macro.
|
| DEFINE_INSTRUCTION(Ror);
|
| + DEFINE_INSTRUCTION(Dror);
|
|
|
| #undef DEFINE_INSTRUCTION
|
| #undef DEFINE_INSTRUCTION2
|
| @@ -608,10 +636,12 @@ class MacroAssembler: public Assembler {
|
|
|
| void Ulw(Register rd, const MemOperand& rs);
|
| void Usw(Register rd, const MemOperand& rs);
|
| + void Uld(Register rd, const MemOperand& rs, Register scratch = at);
|
| + void Usd(Register rd, const MemOperand& rs, Register scratch = at);
|
|
|
| // Load int32 in the rd register.
|
| void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE);
|
| - inline void li(Register rd, int32_t j, LiFlags mode = OPTIMIZE_SIZE) {
|
| + inline void li(Register rd, int64_t j, LiFlags mode = OPTIMIZE_SIZE) {
|
| li(rd, Operand(j), mode);
|
| }
|
| void li(Register dst, Handle<Object> value, LiFlags mode = OPTIMIZE_SIZE);
|
| @@ -626,8 +656,8 @@ class MacroAssembler: public Assembler {
|
| void MultiPushReversedFPU(RegList regs);
|
|
|
| void push(Register src) {
|
| - Addu(sp, sp, Operand(-kPointerSize));
|
| - sw(src, MemOperand(sp, 0));
|
| + Daddu(sp, sp, Operand(-kPointerSize));
|
| + sd(src, MemOperand(sp, 0));
|
| }
|
| void Push(Register src) { push(src); }
|
|
|
| @@ -637,35 +667,38 @@ class MacroAssembler: public Assembler {
|
|
|
| // Push two registers. Pushes leftmost register first (to highest address).
|
| void Push(Register src1, Register src2) {
|
| - Subu(sp, sp, Operand(2 * kPointerSize));
|
| - sw(src1, MemOperand(sp, 1 * kPointerSize));
|
| - sw(src2, MemOperand(sp, 0 * kPointerSize));
|
| + Dsubu(sp, sp, Operand(2 * kPointerSize));
|
| + sd(src1, MemOperand(sp, 1 * kPointerSize));
|
| + sd(src2, MemOperand(sp, 0 * kPointerSize));
|
| }
|
|
|
| // Push three registers. Pushes leftmost register first (to highest address).
|
| void Push(Register src1, Register src2, Register src3) {
|
| - Subu(sp, sp, Operand(3 * kPointerSize));
|
| - sw(src1, MemOperand(sp, 2 * kPointerSize));
|
| - sw(src2, MemOperand(sp, 1 * kPointerSize));
|
| - sw(src3, MemOperand(sp, 0 * kPointerSize));
|
| + Dsubu(sp, sp, Operand(3 * kPointerSize));
|
| + sd(src1, MemOperand(sp, 2 * kPointerSize));
|
| + sd(src2, MemOperand(sp, 1 * kPointerSize));
|
| + sd(src3, MemOperand(sp, 0 * kPointerSize));
|
| }
|
|
|
| // Push four registers. Pushes leftmost register first (to highest address).
|
| void Push(Register src1, Register src2, Register src3, Register src4) {
|
| - Subu(sp, sp, Operand(4 * kPointerSize));
|
| - sw(src1, MemOperand(sp, 3 * kPointerSize));
|
| - sw(src2, MemOperand(sp, 2 * kPointerSize));
|
| - sw(src3, MemOperand(sp, 1 * kPointerSize));
|
| - sw(src4, MemOperand(sp, 0 * kPointerSize));
|
| + Dsubu(sp, sp, Operand(4 * kPointerSize));
|
| + sd(src1, MemOperand(sp, 3 * kPointerSize));
|
| + sd(src2, MemOperand(sp, 2 * kPointerSize));
|
| + sd(src3, MemOperand(sp, 1 * kPointerSize));
|
| + sd(src4, MemOperand(sp, 0 * kPointerSize));
|
| }
|
|
|
| void Push(Register src, Condition cond, Register tst1, Register tst2) {
|
| // Since we don't have conditional execution we use a Branch.
|
| Branch(3, cond, tst1, Operand(tst2));
|
| - Subu(sp, sp, Operand(kPointerSize));
|
| - sw(src, MemOperand(sp, 0));
|
| + Dsubu(sp, sp, Operand(kPointerSize));
|
| + sd(src, MemOperand(sp, 0));
|
| }
|
|
|
| + void PushRegisterAsTwoSmis(Register src, Register scratch = at);
|
| + void PopRegisterAsTwoSmis(Register dst, Register scratch = at);
|
| +
|
| // Pops multiple values from the stack and load them in the
|
| // registers specified in regs. Pop order is the opposite as in MultiPush.
|
| void MultiPop(RegList regs);
|
| @@ -675,29 +708,29 @@ class MacroAssembler: public Assembler {
|
| void MultiPopReversedFPU(RegList regs);
|
|
|
| void pop(Register dst) {
|
| - lw(dst, MemOperand(sp, 0));
|
| - Addu(sp, sp, Operand(kPointerSize));
|
| + ld(dst, MemOperand(sp, 0));
|
| + Daddu(sp, sp, Operand(kPointerSize));
|
| }
|
| void Pop(Register dst) { pop(dst); }
|
|
|
| // Pop two registers. Pops rightmost register first (from lower address).
|
| void Pop(Register src1, Register src2) {
|
| ASSERT(!src1.is(src2));
|
| - lw(src2, MemOperand(sp, 0 * kPointerSize));
|
| - lw(src1, MemOperand(sp, 1 * kPointerSize));
|
| - Addu(sp, sp, 2 * kPointerSize);
|
| + ld(src2, MemOperand(sp, 0 * kPointerSize));
|
| + ld(src1, MemOperand(sp, 1 * kPointerSize));
|
| + Daddu(sp, sp, 2 * kPointerSize);
|
| }
|
|
|
| // Pop three registers. Pops rightmost register first (from lower address).
|
| void Pop(Register src1, Register src2, Register src3) {
|
| - lw(src3, MemOperand(sp, 0 * kPointerSize));
|
| - lw(src2, MemOperand(sp, 1 * kPointerSize));
|
| - lw(src1, MemOperand(sp, 2 * kPointerSize));
|
| - Addu(sp, sp, 3 * kPointerSize);
|
| + ld(src3, MemOperand(sp, 0 * kPointerSize));
|
| + ld(src2, MemOperand(sp, 1 * kPointerSize));
|
| + ld(src1, MemOperand(sp, 2 * kPointerSize));
|
| + Daddu(sp, sp, 3 * kPointerSize);
|
| }
|
|
|
| void Pop(uint32_t count = 1) {
|
| - Addu(sp, sp, Operand(count * kPointerSize));
|
| + Daddu(sp, sp, Operand(count * kPointerSize));
|
| }
|
|
|
| // Push and pop the registers that can hold pointers, as defined by the
|
| @@ -719,7 +752,7 @@ class MacroAssembler: public Assembler {
|
| // Does not handle errors.
|
| void FlushICache(Register address, unsigned instructions);
|
|
|
| - // MIPS32 R2 instruction macro.
|
| + // MIPS64 R2 instruction macro.
|
| void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
|
| void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
|
|
|
| @@ -730,6 +763,14 @@ class MacroAssembler: public Assembler {
|
| void Cvt_d_uw(FPURegister fd, FPURegister fs, FPURegister scratch);
|
| void Cvt_d_uw(FPURegister fd, Register rs, FPURegister scratch);
|
|
|
| + // Convert double to unsigned long.
|
| + void Trunc_l_ud(FPURegister fd, FPURegister fs, FPURegister scratch);
|
| +
|
| + void Trunc_l_d(FPURegister fd, FPURegister fs);
|
| + void Round_l_d(FPURegister fd, FPURegister fs);
|
| + void Floor_l_d(FPURegister fd, FPURegister fs);
|
| + void Ceil_l_d(FPURegister fd, FPURegister fs);
|
| +
|
| // Convert double to unsigned word.
|
| void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch);
|
| void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch);
|
| @@ -738,6 +779,13 @@ class MacroAssembler: public Assembler {
|
| void Round_w_d(FPURegister fd, FPURegister fs);
|
| void Floor_w_d(FPURegister fd, FPURegister fs);
|
| void Ceil_w_d(FPURegister fd, FPURegister fs);
|
| +
|
| + void Madd_d(FPURegister fd,
|
| + FPURegister fr,
|
| + FPURegister fs,
|
| + FPURegister ft,
|
| + FPURegister scratch);
|
| +
|
| // Wrapper function for the different cmp/branch types.
|
| void BranchF(Label* target,
|
| Label* nan,
|
| @@ -1069,7 +1117,7 @@ class MacroAssembler: public Assembler {
|
| Condition IsObjectStringType(Register obj,
|
| Register type,
|
| Register result) {
|
| - lw(type, FieldMemOperand(obj, HeapObject::kMapOffset));
|
| + ld(type, FieldMemOperand(obj, HeapObject::kMapOffset));
|
| lbu(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
|
| And(type, type, Operand(kIsNotStringMask));
|
| ASSERT_EQ(0, kStringTag);
|
| @@ -1224,7 +1272,7 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
|
|
| // Arguments 1-4 are placed in registers a0 thru a3 respectively.
|
| // Arguments 5..n are stored to stack using following:
|
| - // sw(t0, CFunctionArgumentOperand(5));
|
| + // sw(a4, CFunctionArgumentOperand(5));
|
|
|
| // Calls a C function and cleans up the space for arguments allocated
|
| // by PrepareCallCFunction. The called function is not allowed to trigger a
|
| @@ -1338,16 +1386,22 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
| // -------------------------------------------------------------------------
|
| // Smi utilities.
|
|
|
| - void SmiTag(Register reg) {
|
| - Addu(reg, reg, reg);
|
| - }
|
| -
|
| // Test for overflow < 0: use BranchOnOverflow() or BranchOnNoOverflow().
|
| void SmiTagCheckOverflow(Register reg, Register overflow);
|
| void SmiTagCheckOverflow(Register dst, Register src, Register overflow);
|
|
|
| void SmiTag(Register dst, Register src) {
|
| - Addu(dst, src, src);
|
| + STATIC_ASSERT(kSmiTag == 0);
|
| + if (SmiValuesAre32Bits()) {
|
| + STATIC_ASSERT(kSmiShift == 32);
|
| + dsll32(dst, src, 0);
|
| + } else {
|
| + Addu(dst, src, src);
|
| + }
|
| + }
|
| +
|
| + void SmiTag(Register reg) {
|
| + SmiTag(reg, reg);
|
| }
|
|
|
| // Try to convert int32 to smi. If the value is to large, preserve
|
| @@ -1356,23 +1410,62 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
| void TrySmiTag(Register reg, Register scratch, Label* not_a_smi) {
|
| TrySmiTag(reg, reg, scratch, not_a_smi);
|
| }
|
| +
|
| void TrySmiTag(Register dst,
|
| Register src,
|
| Register scratch,
|
| Label* not_a_smi) {
|
| - SmiTagCheckOverflow(at, src, scratch);
|
| - BranchOnOverflow(not_a_smi, scratch);
|
| - mov(dst, at);
|
| + if (SmiValuesAre32Bits()) {
|
| + SmiTag(dst, src);
|
| + } else {
|
| + SmiTagCheckOverflow(at, src, scratch);
|
| + BranchOnOverflow(not_a_smi, scratch);
|
| + mov(dst, at);
|
| + }
|
| + }
|
| +
|
| + void SmiUntag(Register dst, Register src) {
|
| + if (SmiValuesAre32Bits()) {
|
| + STATIC_ASSERT(kSmiShift == 32);
|
| + dsra32(dst, src, 0);
|
| + } else {
|
| + sra(dst, src, kSmiTagSize);
|
| + }
|
| }
|
|
|
| void SmiUntag(Register reg) {
|
| - sra(reg, reg, kSmiTagSize);
|
| + SmiUntag(reg, reg);
|
| }
|
|
|
| - void SmiUntag(Register dst, Register src) {
|
| - sra(dst, src, kSmiTagSize);
|
| + // Left-shifted from int32 equivalent of Smi.
|
| + void SmiScale(Register dst, Register src, int scale) {
|
| + if (SmiValuesAre32Bits()) {
|
| + // The int portion is upper 32-bits of 64-bit word.
|
| + dsra(dst, src, kSmiShift - scale);
|
| + } else {
|
| + ASSERT(scale >= kSmiTagSize);
|
| + sll(dst, src, scale - kSmiTagSize);
|
| + }
|
| }
|
|
|
| + // Combine load with untagging or scaling.
|
| + void SmiLoadUntag(Register dst, MemOperand src);
|
| +
|
| + void SmiLoadScale(Register dst, MemOperand src, int scale);
|
| +
|
| + // Returns 2 values: the Smi and a scaled version of the int within the Smi.
|
| + void SmiLoadWithScale(Register d_smi,
|
| + Register d_scaled,
|
| + MemOperand src,
|
| + int scale);
|
| +
|
| + // Returns 2 values: the untagged Smi (int32) and scaled version of that int.
|
| + void SmiLoadUntagWithScale(Register d_int,
|
| + Register d_scaled,
|
| + MemOperand src,
|
| + int scale);
|
| +
|
| +
|
| // Test if the register contains a smi.
|
| inline void SmiTst(Register value, Register scratch) {
|
| And(scratch, value, Operand(kSmiTagMask));
|
| @@ -1382,11 +1475,11 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
| }
|
|
|
| // Untag the source value into destination and jump if source is a smi.
|
| - // Souce and destination can be the same register.
|
| + // Source and destination can be the same register.
|
| void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case);
|
|
|
| // Untag the source value into destination and jump if source is not a smi.
|
| - // Souce and destination can be the same register.
|
| + // Source and destination can be the same register.
|
| void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case);
|
|
|
| // Jump the register contains a smi.
|
| @@ -1510,25 +1603,16 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
| template<typename Field>
|
| void DecodeFieldToSmi(Register dst, Register src) {
|
| static const int shift = Field::kShift;
|
| - static const int mask = Field::kMask >> shift << kSmiTagSize;
|
| - STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - if (shift < kSmiTagSize) {
|
| - sll(dst, src, kSmiTagSize - shift);
|
| - And(dst, dst, Operand(mask));
|
| - } else if (shift > kSmiTagSize) {
|
| - srl(dst, src, shift - kSmiTagSize);
|
| - And(dst, dst, Operand(mask));
|
| - } else {
|
| - And(dst, src, Operand(mask));
|
| - }
|
| + static const int mask = Field::kMask >> shift;
|
| + dsrl(dst, src, shift);
|
| + And(dst, dst, Operand(mask));
|
| + dsll32(dst, dst, 0);
|
| }
|
|
|
| template<typename Field>
|
| void DecodeFieldToSmi(Register reg) {
|
| DecodeField<Field>(reg, reg);
|
| }
|
| -
|
| // Generates function and stub prologue code.
|
| void StubPrologue();
|
| void Prologue(bool code_pre_aging);
|
|
|