Index: runtime/vm/assembler_mips.h |
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h |
deleted file mode 100644 |
index 7073e3078830b282307b06d35b3b03f4fb5be6e4..0000000000000000000000000000000000000000 |
--- a/runtime/vm/assembler_mips.h |
+++ /dev/null |
@@ -1,1722 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-#ifndef RUNTIME_VM_ASSEMBLER_MIPS_H_ |
-#define RUNTIME_VM_ASSEMBLER_MIPS_H_ |
- |
-#ifndef RUNTIME_VM_ASSEMBLER_H_ |
-#error Do not include assembler_mips.h directly; use assembler.h instead. |
-#endif |
- |
-#include "platform/assert.h" |
-#include "platform/utils.h" |
-#include "vm/constants_mips.h" |
-#include "vm/hash_map.h" |
-#include "vm/object.h" |
-#include "vm/simulator.h" |
- |
-// References to documentation in this file refer to: |
-// "MIPS® Architecture For Programmers Volume I-A: |
-// Introduction to the MIPS32® Architecture" in short "VolI-A" |
-// and |
-// "MIPS® Architecture For Programmers Volume II-A: |
-// The MIPS32® Instruction Set" in short "VolII-A" |
-namespace dart { |
- |
-// Forward declarations. |
-class RuntimeEntry; |
-class StubEntry; |
- |
-class Immediate : public ValueObject { |
- public: |
- explicit Immediate(int32_t value) : value_(value) {} |
- |
- Immediate(const Immediate& other) : ValueObject(), value_(other.value_) {} |
- Immediate& operator=(const Immediate& other) { |
- value_ = other.value_; |
- return *this; |
- } |
- |
- private: |
- int32_t value_; |
- |
- int32_t value() const { return value_; } |
- |
- friend class Assembler; |
-}; |
- |
- |
-class Address : public ValueObject { |
- public: |
- explicit Address(Register base, int32_t offset = 0) |
- : ValueObject(), base_(base), offset_(offset) {} |
- |
- // This addressing mode does not exist. |
- Address(Register base, Register offset); |
- |
- Address(const Address& other) |
- : ValueObject(), base_(other.base_), offset_(other.offset_) {} |
- Address& operator=(const Address& other) { |
- base_ = other.base_; |
- offset_ = other.offset_; |
- return *this; |
- } |
- |
- uint32_t encoding() const { |
- ASSERT(Utils::IsInt(kImmBits, offset_)); |
- uint16_t imm_value = static_cast<uint16_t>(offset_); |
- return (base_ << kRsShift) | imm_value; |
- } |
- |
- static bool CanHoldOffset(int32_t offset) { |
- return Utils::IsInt(kImmBits, offset); |
- } |
- |
- Register base() const { return base_; } |
- int32_t offset() const { return offset_; } |
- |
- private: |
- Register base_; |
- int32_t offset_; |
-}; |
- |
- |
-class FieldAddress : public Address { |
- public: |
- FieldAddress(Register base, int32_t disp) |
- : Address(base, disp - kHeapObjectTag) {} |
- |
- FieldAddress(const FieldAddress& other) : Address(other) {} |
- |
- FieldAddress& operator=(const FieldAddress& other) { |
- Address::operator=(other); |
- return *this; |
- } |
-}; |
- |
- |
-class Label : public ValueObject { |
- public: |
- Label() : position_(0) {} |
- |
- ~Label() { |
- // Assert if label is being destroyed with unresolved branches pending. |
- ASSERT(!IsLinked()); |
- } |
- |
- // Returns the position for bound and linked labels. Cannot be used |
- // for unused labels. |
- intptr_t Position() const { |
- ASSERT(!IsUnused()); |
- return IsBound() ? -position_ - kWordSize : position_ - kWordSize; |
- } |
- |
- bool IsBound() const { return position_ < 0; } |
- bool IsUnused() const { return position_ == 0; } |
- bool IsLinked() const { return position_ > 0; } |
- |
- private: |
- intptr_t position_; |
- |
- void Reinitialize() { position_ = 0; } |
- |
- void BindTo(intptr_t position) { |
- ASSERT(!IsBound()); |
- position_ = -position - kWordSize; |
- ASSERT(IsBound()); |
- } |
- |
- void LinkTo(intptr_t position) { |
- ASSERT(!IsBound()); |
- position_ = position + kWordSize; |
- ASSERT(IsLinked()); |
- } |
- |
- friend class Assembler; |
- DISALLOW_COPY_AND_ASSIGN(Label); |
-}; |
- |
- |
-// There is no dedicated status register on MIPS, but Condition values are used |
-// and passed around by the intermediate language, so we need a Condition type. |
-// We delay code generation of a comparison that would result in a traditional |
-// condition code in the status register by keeping both register operands and |
-// the relational operator between them as the Condition. |
-class Condition : public ValueObject { |
- public: |
- enum Bits { |
- kLeftPos = 0, |
- kLeftSize = 6, |
- kRightPos = kLeftPos + kLeftSize, |
- kRightSize = 6, |
- kRelOpPos = kRightPos + kRightSize, |
- kRelOpSize = 4, |
- kImmPos = kRelOpPos + kRelOpSize, |
- kImmSize = 16, |
- }; |
- |
- class LeftBits : public BitField<uword, Register, kLeftPos, kLeftSize> {}; |
- class RightBits : public BitField<uword, Register, kRightPos, kRightSize> {}; |
- class RelOpBits |
- : public BitField<uword, RelationOperator, kRelOpPos, kRelOpSize> {}; |
- class ImmBits : public BitField<uword, uint16_t, kImmPos, kImmSize> {}; |
- |
- Register left() const { |
- ASSERT(IsValid()); |
- return LeftBits::decode(bits_); |
- } |
- |
- Register right() const { |
- ASSERT(IsValid()); |
- return RightBits::decode(bits_); |
- } |
- RelationOperator rel_op() const { return RelOpBits::decode(bits_); } |
- int16_t imm() const { |
- ASSERT(IsValid()); |
- return static_cast<int16_t>(ImmBits::decode(bits_)); |
- } |
- |
- static bool IsValidImm(int32_t value) { |
- // We want both value and value + 1 to fit in an int16_t. |
- return (-0x08000 <= value) && (value < 0x7fff); |
- } |
- |
- void set_rel_op(RelationOperator value) { |
- ASSERT(IsValidRelOp(value)); |
- bits_ = RelOpBits::update(value, bits_); |
- } |
- |
- bool IsValid() const { return rel_op() != INVALID_RELATION; } |
- |
- // Uninitialized condition. |
- Condition() : ValueObject(), bits_(RelOpBits::update(INVALID_RELATION, 0)) {} |
- |
- // Copy constructor. |
- Condition(const Condition& other) : ValueObject(), bits_(other.bits_) {} |
- |
- // Copy assignment operator. |
- Condition& operator=(const Condition& other) { |
- bits_ = other.bits_; |
- return *this; |
- } |
- |
- Condition(Register left, |
- Register right, |
- RelationOperator rel_op, |
- int16_t imm = 0) { |
- // At most one constant, ZR or immediate. |
- ASSERT(!(((left == ZR) || (left == IMM)) && |
- ((right == ZR) || (right == IMM)))); |
- // Non-zero immediate value is only allowed for IMM. |
- ASSERT((imm != 0) == ((left == IMM) || (right == IMM))); |
- set_left(left); |
- set_right(right); |
- if (rel_op == INVALID_RELATION) { |
- SetToInvalidState(); |
- } else { |
- set_rel_op(rel_op); |
- } |
- set_imm(imm); |
- } |
- |
- private: |
- void SetToInvalidState() { |
- bits_ = RelOpBits::update(INVALID_RELATION, bits_); |
- } |
- |
- static bool IsValidRelOp(RelationOperator value) { |
- return (AL <= value) && (value <= ULE); |
- } |
- |
- static bool IsValidRegister(Register value) { |
- return (ZR <= value) && (value <= IMM) && (value != AT); |
- } |
- |
- void set_left(Register value) { |
- ASSERT(IsValidRegister(value)); |
- bits_ = LeftBits::update(value, bits_); |
- } |
- |
- void set_right(Register value) { |
- ASSERT(IsValidRegister(value)); |
- bits_ = RightBits::update(value, bits_); |
- } |
- |
- void set_imm(int16_t value) { |
- ASSERT(IsValidImm(value)); |
- bits_ = ImmBits::update(static_cast<uint16_t>(value), bits_); |
- } |
- |
- uword bits_; |
-}; |
- |
- |
-class Assembler : public ValueObject { |
- public: |
- explicit Assembler(bool use_far_branches = false) |
- : buffer_(), |
- prologue_offset_(-1), |
- has_single_entry_point_(true), |
- use_far_branches_(use_far_branches), |
- delay_slot_available_(false), |
- in_delay_slot_(false), |
- comments_(), |
- constant_pool_allowed_(true) {} |
- ~Assembler() {} |
- |
- void PopRegister(Register r) { Pop(r); } |
- |
- void Bind(Label* label); |
- void Jump(Label* label) { b(label); } |
- |
- // Misc. functionality |
- intptr_t CodeSize() const { return buffer_.Size(); } |
- intptr_t prologue_offset() const { return prologue_offset_; } |
- bool has_single_entry_point() const { return has_single_entry_point_; } |
- |
- // Count the fixups that produce a pointer offset, without processing |
- // the fixups. |
- intptr_t CountPointerOffsets() const { return buffer_.CountPointerOffsets(); } |
- |
- const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { |
- return buffer_.pointer_offsets(); |
- } |
- |
- ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } |
- |
- RawObjectPool* MakeObjectPool() { |
- return object_pool_wrapper_.MakeObjectPool(); |
- } |
- |
- void FinalizeInstructions(const MemoryRegion& region) { |
- buffer_.FinalizeInstructions(region); |
- } |
- |
- bool use_far_branches() const { |
- return FLAG_use_far_branches || use_far_branches_; |
- } |
- |
- void set_use_far_branches(bool b) { use_far_branches_ = b; } |
- |
- void EnterFrame(); |
- void LeaveFrameAndReturn(); |
- |
- // Set up a stub frame so that the stack traversal code can easily identify |
- // a stub frame. |
- void EnterStubFrame(intptr_t frame_size = 0); |
- void LeaveStubFrame(); |
- // A separate macro for when a Ret immediately follows, so that we can use |
- // the branch delay slot. |
- void LeaveStubFrameAndReturn(Register ra = RA); |
- |
- void MonomorphicCheckedEntry(); |
- |
- void UpdateAllocationStats(intptr_t cid, |
- Register temp_reg, |
- Heap::Space space); |
- |
- void UpdateAllocationStatsWithSize(intptr_t cid, |
- Register size_reg, |
- Register temp_reg, |
- Heap::Space space); |
- |
- |
- void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label* trace); |
- |
- // Inlined allocation of an instance of class 'cls', code has no runtime |
- // calls. Jump to 'failure' if the instance cannot be allocated here. |
- // Allocated instance is returned in 'instance_reg'. |
- // Only the tags field of the object is initialized. |
- void TryAllocate(const Class& cls, |
- Label* failure, |
- Register instance_reg, |
- Register temp_reg); |
- |
- void TryAllocateArray(intptr_t cid, |
- intptr_t instance_size, |
- Label* failure, |
- Register instance, |
- Register end_address, |
- Register temp1, |
- Register temp2); |
- |
- // Debugging and bringup support. |
- void Stop(const char* message); |
- void Unimplemented(const char* message); |
- void Untested(const char* message); |
- void Unreachable(const char* message); |
- |
- static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); |
- |
- void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
- static bool EmittingComments(); |
- |
- const Code::Comments& GetCodeComments() const; |
- |
- static const char* RegisterName(Register reg); |
- |
- static const char* FpuRegisterName(FpuRegister reg); |
- |
- void SetPrologueOffset() { |
- if (prologue_offset_ == -1) { |
- prologue_offset_ = CodeSize(); |
- } |
- } |
- |
- // A utility to be able to assemble an instruction into the delay slot. |
- Assembler* delay_slot() { |
- ASSERT(delay_slot_available_); |
- ASSERT(buffer_.Load<int32_t>(buffer_.GetPosition() - sizeof(int32_t)) == |
- Instr::kNopInstruction); |
- buffer_.Remit<int32_t>(); |
- delay_slot_available_ = false; |
- in_delay_slot_ = true; |
- return this; |
- } |
- |
- // CPU instructions in alphabetical order. |
- void addd(DRegister dd, DRegister ds, DRegister dt) { |
- // DRegisters start at the even FRegisters. |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_ADD); |
- } |
- |
- void addiu(Register rt, Register rs, const Immediate& imm) { |
- ASSERT(Utils::IsInt(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(ADDIU, rs, rt, imm_value); |
- } |
- |
- void addu(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, ADDU); |
- } |
- |
- void and_(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, AND); |
- } |
- |
- void andi(Register rt, Register rs, const Immediate& imm) { |
- ASSERT(Utils::IsUint(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(ANDI, rs, rt, imm_value); |
- } |
- |
- // Unconditional branch. |
- void b(Label* l) { beq(R0, R0, l); } |
- |
- void bal(Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitRegImmBranch(BGEZAL, R0, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch on floating point false. |
- void bc1f(Label* l) { |
- EmitFpuBranch(false, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch on floating point true. |
- void bc1t(Label* l) { |
- EmitFpuBranch(true, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if equal. |
- void beq(Register rs, Register rt, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitBranch(BEQ, rs, rt, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if equal, likely taken. |
- // Delay slot executed only when branch taken. |
- void beql(Register rs, Register rt, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitBranch(BEQL, rs, rt, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs >= 0. |
- void bgez(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitRegImmBranch(BGEZ, rs, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs >= 0, likely taken. |
- // Delay slot executed only when branch taken. |
- void bgezl(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitRegImmBranch(BGEZL, rs, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs > 0. |
- void bgtz(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitBranch(BGTZ, rs, R0, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs > 0, likely taken. |
- // Delay slot executed only when branch taken. |
- void bgtzl(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitBranch(BGTZL, rs, R0, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs <= 0. |
- void blez(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitBranch(BLEZ, rs, R0, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs <= 0, likely taken. |
- // Delay slot executed only when branch taken. |
- void blezl(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitBranch(BLEZL, rs, R0, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs < 0. |
- void bltz(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitRegImmBranch(BLTZ, rs, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if rs < 0, likely taken. |
- // Delay slot executed only when branch taken. |
- void bltzl(Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- EmitRegImmBranch(BLTZL, rs, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if not equal. |
- void bne(Register rs, Register rt, Label* l) { |
- ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
- EmitBranch(BNE, rs, rt, l); |
- EmitBranchDelayNop(); |
- } |
- |
- // Branch if not equal, likely taken. |
- // Delay slot executed only when branch taken. |
- void bnel(Register rs, Register rt, Label* l) { |
- ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
- EmitBranch(BNEL, rs, rt, l); |
- EmitBranchDelayNop(); |
- } |
- |
- static int32_t BreakEncoding(int32_t code) { |
- ASSERT(Utils::IsUint(20, code)); |
- return SPECIAL << kOpcodeShift | code << kBreakCodeShift | |
- BREAK << kFunctionShift; |
- } |
- |
- |
- void break_(int32_t code) { Emit(BreakEncoding(code)); } |
- |
- static uword GetBreakInstructionFiller() { return BreakEncoding(0); } |
- |
- // FPU compare, always false. |
- void cfd(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_F); |
- } |
- |
- // FPU compare, true if unordered, i.e. one is NaN. |
- void cund(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_UN); |
- } |
- |
- // FPU compare, true if equal. |
- void ceqd(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_EQ); |
- } |
- |
- // FPU compare, true if unordered or equal. |
- void cueqd(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_UEQ); |
- } |
- |
- // FPU compare, true if less than. |
- void coltd(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_OLT); |
- } |
- |
- // FPU compare, true if unordered or less than. |
- void cultd(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_ULT); |
- } |
- |
- // FPU compare, true if less or equal. |
- void coled(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_OLE); |
- } |
- |
- // FPU compare, true if unordered or less or equal. |
- void culed(DRegister ds, DRegister dt) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_ULE); |
- } |
- |
- void clo(Register rd, Register rs) { |
- EmitRType(SPECIAL2, rs, rd, rd, 0, CLO); |
- } |
- |
- void clz(Register rd, Register rs) { |
- EmitRType(SPECIAL2, rs, rd, rd, 0, CLZ); |
- } |
- |
- // Convert a double in ds to a 32-bit signed int in fd rounding towards 0. |
- void truncwd(FRegister fd, DRegister ds) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_TRUNC_W); |
- } |
- |
- // Convert a 32-bit float in fs to a 64-bit double in dd. |
- void cvtds(DRegister dd, FRegister fs) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_CVT_D); |
- } |
- |
- // Converts a 32-bit signed int in fs to a double in fd. |
- void cvtdw(DRegister dd, FRegister fs) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- EmitFpuRType(COP1, FMT_W, F0, fs, fd, COP1_CVT_D); |
- } |
- |
- // Convert a 64-bit double in ds to a 32-bit float in fd. |
- void cvtsd(FRegister fd, DRegister ds) { |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_S); |
- } |
- |
- void div(Register rs, Register rt) { EmitRType(SPECIAL, rs, rt, R0, 0, DIV); } |
- |
- void divd(DRegister dd, DRegister ds, DRegister dt) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_DIV); |
- } |
- |
- void divu(Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, R0, 0, DIVU); |
- } |
- |
- void jalr(Register rs, Register rd = RA) { |
- ASSERT(rs != rd); |
- ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
- EmitRType(SPECIAL, rs, R0, rd, 0, JALR); |
- EmitBranchDelayNop(); |
- } |
- |
- void jr(Register rs) { |
- ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
- EmitRType(SPECIAL, rs, R0, R0, 0, JR); |
- EmitBranchDelayNop(); |
- } |
- |
- void lb(Register rt, const Address& addr) { EmitLoadStore(LB, rt, addr); } |
- |
- void lbu(Register rt, const Address& addr) { EmitLoadStore(LBU, rt, addr); } |
- |
- void ldc1(DRegister dt, const Address& addr) { |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuLoadStore(LDC1, ft, addr); |
- } |
- |
- void lh(Register rt, const Address& addr) { EmitLoadStore(LH, rt, addr); } |
- |
- void lhu(Register rt, const Address& addr) { EmitLoadStore(LHU, rt, addr); } |
- |
- void ll(Register rt, const Address& addr) { EmitLoadStore(LL, rt, addr); } |
- |
- void lui(Register rt, const Immediate& imm) { |
- ASSERT(Utils::IsUint(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(LUI, R0, rt, imm_value); |
- } |
- |
- void lw(Register rt, const Address& addr) { EmitLoadStore(LW, rt, addr); } |
- |
- void lwc1(FRegister ft, const Address& addr) { |
- EmitFpuLoadStore(LWC1, ft, addr); |
- } |
- |
- void madd(Register rs, Register rt) { |
- EmitRType(SPECIAL2, rs, rt, R0, 0, MADD); |
- } |
- |
- void maddu(Register rs, Register rt) { |
- EmitRType(SPECIAL2, rs, rt, R0, 0, MADDU); |
- } |
- |
- void mfc1(Register rt, FRegister fs) { |
- Emit(COP1 << kOpcodeShift | COP1_MF << kCop1SubShift | rt << kRtShift | |
- fs << kFsShift); |
- } |
- |
- void mfhi(Register rd) { EmitRType(SPECIAL, R0, R0, rd, 0, MFHI); } |
- |
- void mflo(Register rd) { EmitRType(SPECIAL, R0, R0, rd, 0, MFLO); } |
- |
- void mov(Register rd, Register rs) { or_(rd, rs, ZR); } |
- |
- void movd(DRegister dd, DRegister ds) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_MOV); |
- } |
- |
- // Move if floating point false. |
- void movf(Register rd, Register rs) { |
- EmitRType(SPECIAL, rs, R0, rd, 0, MOVCI); |
- } |
- |
- void movn(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, MOVN); |
- } |
- |
- // Move if floating point true. |
- void movt(Register rd, Register rs) { |
- EmitRType(SPECIAL, rs, R1, rd, 0, MOVCI); |
- } |
- |
- // rd <- (rt == 0) ? rs : rd; |
- void movz(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, MOVZ); |
- } |
- |
- void movs(FRegister fd, FRegister fs) { |
- EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_MOV); |
- } |
- |
- void mtc1(Register rt, FRegister fs) { |
- Emit(COP1 << kOpcodeShift | COP1_MT << kCop1SubShift | rt << kRtShift | |
- fs << kFsShift); |
- } |
- |
- void mthi(Register rs) { EmitRType(SPECIAL, rs, R0, R0, 0, MTHI); } |
- |
- void mtlo(Register rs) { EmitRType(SPECIAL, rs, R0, R0, 0, MTLO); } |
- |
- void muld(DRegister dd, DRegister ds, DRegister dt) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_MUL); |
- } |
- |
- void mult(Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, R0, 0, MULT); |
- } |
- |
- void multu(Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, R0, 0, MULTU); |
- } |
- |
- void negd(DRegister dd, DRegister ds) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_NEG); |
- } |
- |
- void nop() { Emit(Instr::kNopInstruction); } |
- |
- void nor(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, NOR); |
- } |
- |
- void or_(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, OR); |
- } |
- |
- void ori(Register rt, Register rs, const Immediate& imm) { |
- ASSERT(Utils::IsUint(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(ORI, rs, rt, imm_value); |
- } |
- |
- void sb(Register rt, const Address& addr) { EmitLoadStore(SB, rt, addr); } |
- |
- // rt = 1 on success, 0 on failure. |
- void sc(Register rt, const Address& addr) { EmitLoadStore(SC, rt, addr); } |
- |
- void sdc1(DRegister dt, const Address& addr) { |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuLoadStore(SDC1, ft, addr); |
- } |
- |
- void sh(Register rt, const Address& addr) { EmitLoadStore(SH, rt, addr); } |
- |
- void sll(Register rd, Register rt, int sa) { |
- EmitRType(SPECIAL, R0, rt, rd, sa, SLL); |
- } |
- |
- void sllv(Register rd, Register rt, Register rs) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, SLLV); |
- } |
- |
- void slt(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, SLT); |
- } |
- |
- void slti(Register rt, Register rs, const Immediate& imm) { |
- ASSERT(Utils::IsInt(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(SLTI, rs, rt, imm_value); |
- } |
- |
- // Although imm argument is int32_t, it is interpreted as an uint32_t. |
- // For example, -1 stands for 0xffffffffUL: it is encoded as 0xffff in the |
- // instruction imm field and is then sign extended back to 0xffffffffUL. |
- void sltiu(Register rt, Register rs, const Immediate& imm) { |
- ASSERT(Utils::IsInt(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(SLTIU, rs, rt, imm_value); |
- } |
- |
- void sltu(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, SLTU); |
- } |
- |
- void sqrtd(DRegister dd, DRegister ds) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_SQRT); |
- } |
- |
- void sra(Register rd, Register rt, int sa) { |
- EmitRType(SPECIAL, R0, rt, rd, sa, SRA); |
- } |
- |
- void srav(Register rd, Register rt, Register rs) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, SRAV); |
- } |
- |
- void srl(Register rd, Register rt, int sa) { |
- EmitRType(SPECIAL, R0, rt, rd, sa, SRL); |
- } |
- |
- void srlv(Register rd, Register rt, Register rs) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, SRLV); |
- } |
- |
- void subd(DRegister dd, DRegister ds, DRegister dt) { |
- FRegister fd = static_cast<FRegister>(dd * 2); |
- FRegister fs = static_cast<FRegister>(ds * 2); |
- FRegister ft = static_cast<FRegister>(dt * 2); |
- EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_SUB); |
- } |
- |
- void subu(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, SUBU); |
- } |
- |
- void sw(Register rt, const Address& addr) { EmitLoadStore(SW, rt, addr); } |
- |
- void swc1(FRegister ft, const Address& addr) { |
- EmitFpuLoadStore(SWC1, ft, addr); |
- } |
- |
- void xori(Register rt, Register rs, const Immediate& imm) { |
- ASSERT(Utils::IsUint(kImmBits, imm.value())); |
- const uint16_t imm_value = static_cast<uint16_t>(imm.value()); |
- EmitIType(XORI, rs, rt, imm_value); |
- } |
- |
- void xor_(Register rd, Register rs, Register rt) { |
- EmitRType(SPECIAL, rs, rt, rd, 0, XOR); |
- } |
- |
- // Macros in alphabetical order. |
- |
- // Addition of rs and rt with the result placed in rd. |
- // After, ro < 0 if there was signed overflow, ro >= 0 otherwise. |
- // rd and ro must not be TMP. |
- // ro must be different from all the other registers. |
- // If rd, rs, and rt are the same register, then a scratch register different |
- // from the other registers is needed. |
- void AdduDetectOverflow(Register rd, |
- Register rs, |
- Register rt, |
- Register ro, |
- Register scratch = kNoRegister); |
- |
- // ro must be different from rd and rs. |
- // rd and ro must not be TMP. |
- // If rd and rs are the same, a scratch register different from the other |
- // registers is needed. |
- void AddImmediateDetectOverflow(Register rd, |
- Register rs, |
- int32_t imm, |
- Register ro, |
- Register scratch = kNoRegister) { |
- ASSERT(!in_delay_slot_); |
- LoadImmediate(rd, imm); |
- AdduDetectOverflow(rd, rs, rd, ro, scratch); |
- } |
- |
- // Subtraction of rt from rs (rs - rt) with the result placed in rd. |
- // After, ro < 0 if there was signed overflow, ro >= 0 otherwise. |
- // None of rd, rs, rt, or ro may be TMP. |
- // ro must be different from the other registers. |
- void SubuDetectOverflow(Register rd, Register rs, Register rt, Register ro); |
- |
- // ro must be different from rd and rs. |
- // None of rd, rs, rt, or ro may be TMP. |
- void SubImmediateDetectOverflow(Register rd, |
- Register rs, |
- int32_t imm, |
- Register ro) { |
- ASSERT(!in_delay_slot_); |
- LoadImmediate(rd, imm); |
- SubuDetectOverflow(rd, rs, rd, ro); |
- } |
- |
- void Branch(const StubEntry& stub_entry, Register pp = PP); |
- |
- void BranchLink(const StubEntry& stub_entry, |
- Patchability patchable = kNotPatchable); |
- |
- void BranchLinkPatchable(const StubEntry& stub_entry); |
- void BranchLinkToRuntime(); |
- |
- // Emit a call that shares its object pool entries with other calls |
- // that have the same equivalence marker. |
- void BranchLinkWithEquivalence(const StubEntry& stub_entry, |
- const Object& equivalence); |
- |
- void Drop(intptr_t stack_elements) { |
- ASSERT(stack_elements >= 0); |
- if (stack_elements > 0) { |
- addiu(SP, SP, Immediate(stack_elements * kWordSize)); |
- } |
- } |
- |
- void LoadPoolPointer(Register reg = PP) { |
- ASSERT(!in_delay_slot_); |
- CheckCodePointer(); |
- lw(reg, FieldAddress(CODE_REG, Code::object_pool_offset())); |
- set_constant_pool_allowed(reg == PP); |
- } |
- |
- void CheckCodePointer(); |
- |
- void RestoreCodePointer(); |
- |
- void LoadImmediate(Register rd, int32_t value) { |
- ASSERT(!in_delay_slot_); |
- if (Utils::IsInt(kImmBits, value)) { |
- addiu(rd, ZR, Immediate(value)); |
- } else { |
- const uint16_t low = Utils::Low16Bits(value); |
- const uint16_t high = Utils::High16Bits(value); |
- lui(rd, Immediate(high)); |
- if (low != 0) { |
- ori(rd, rd, Immediate(low)); |
- } |
- } |
- } |
- |
- void LoadImmediate(DRegister rd, double value) { |
- ASSERT(!in_delay_slot_); |
- FRegister frd = static_cast<FRegister>(rd * 2); |
- const int64_t ival = bit_cast<uint64_t, double>(value); |
- const int32_t low = Utils::Low32Bits(ival); |
- const int32_t high = Utils::High32Bits(ival); |
- if (low != 0) { |
- LoadImmediate(TMP, low); |
- mtc1(TMP, frd); |
- } else { |
- mtc1(ZR, frd); |
- } |
- |
- if (high != 0) { |
- LoadImmediate(TMP, high); |
- mtc1(TMP, static_cast<FRegister>(frd + 1)); |
- } else { |
- mtc1(ZR, static_cast<FRegister>(frd + 1)); |
- } |
- } |
- |
- void LoadImmediate(FRegister rd, float value) { |
- ASSERT(!in_delay_slot_); |
- const int32_t ival = bit_cast<int32_t, float>(value); |
- if (ival == 0) { |
- mtc1(ZR, rd); |
- } else { |
- LoadImmediate(TMP, ival); |
- mtc1(TMP, rd); |
- } |
- } |
- |
- void AddImmediate(Register rd, Register rs, int32_t value) { |
- ASSERT(!in_delay_slot_); |
- if ((value == 0) && (rd == rs)) return; |
- // If value is 0, we still want to move rs to rd if they aren't the same. |
- if (Utils::IsInt(kImmBits, value)) { |
- addiu(rd, rs, Immediate(value)); |
- } else { |
- LoadImmediate(TMP, value); |
- addu(rd, rs, TMP); |
- } |
- } |
- |
- void AddImmediate(Register rd, int32_t value) { |
- ASSERT(!in_delay_slot_); |
- AddImmediate(rd, rd, value); |
- } |
- |
- void AndImmediate(Register rd, Register rs, int32_t imm) { |
- ASSERT(!in_delay_slot_); |
- if (imm == 0) { |
- mov(rd, ZR); |
- return; |
- } |
- |
- if (Utils::IsUint(kImmBits, imm)) { |
- andi(rd, rs, Immediate(imm)); |
- } else { |
- LoadImmediate(TMP, imm); |
- and_(rd, rs, TMP); |
- } |
- } |
- |
- void OrImmediate(Register rd, Register rs, int32_t imm) { |
- ASSERT(!in_delay_slot_); |
- if (imm == 0) { |
- mov(rd, rs); |
- return; |
- } |
- |
- if (Utils::IsUint(kImmBits, imm)) { |
- ori(rd, rs, Immediate(imm)); |
- } else { |
- LoadImmediate(TMP, imm); |
- or_(rd, rs, TMP); |
- } |
- } |
- |
- void XorImmediate(Register rd, Register rs, int32_t imm) { |
- ASSERT(!in_delay_slot_); |
- if (imm == 0) { |
- mov(rd, rs); |
- return; |
- } |
- |
- if (Utils::IsUint(kImmBits, imm)) { |
- xori(rd, rs, Immediate(imm)); |
- } else { |
- LoadImmediate(TMP, imm); |
- xor_(rd, rs, TMP); |
- } |
- } |
- |
- Register LoadConditionOperand(Register rd, |
- const Object& operand, |
- int16_t* imm) { |
- if (operand.IsSmi()) { |
- const int32_t val = reinterpret_cast<int32_t>(operand.raw()); |
- if (val == 0) { |
- return ZR; |
- } else if (Condition::IsValidImm(val)) { |
- ASSERT(*imm == 0); |
- *imm = val; |
- return IMM; |
- } |
- } |
- LoadObject(rd, operand); |
- return rd; |
- } |
- |
- // Branch to label if condition is true. |
- void BranchOnCondition(Condition cond, Label* l) { |
- ASSERT(!in_delay_slot_); |
- Register left = cond.left(); |
- Register right = cond.right(); |
- RelationOperator rel_op = cond.rel_op(); |
- switch (rel_op) { |
- case NV: |
- return; |
- case AL: |
- b(l); |
- return; |
- case EQ: // fall through. |
- case NE: { |
- if (left == IMM) { |
- addiu(AT, ZR, Immediate(cond.imm())); |
- left = AT; |
- } else if (right == IMM) { |
- addiu(AT, ZR, Immediate(cond.imm())); |
- right = AT; |
- } |
- if (rel_op == EQ) { |
- beq(left, right, l); |
- } else { |
- bne(left, right, l); |
- } |
- break; |
- } |
- case GT: { |
- if (left == ZR) { |
- bltz(right, l); |
- } else if (right == ZR) { |
- bgtz(left, l); |
- } else if (left == IMM) { |
- slti(AT, right, Immediate(cond.imm())); |
- bne(AT, ZR, l); |
- } else if (right == IMM) { |
- slti(AT, left, Immediate(cond.imm() + 1)); |
- beq(AT, ZR, l); |
- } else { |
- slt(AT, right, left); |
- bne(AT, ZR, l); |
- } |
- break; |
- } |
- case GE: { |
- if (left == ZR) { |
- blez(right, l); |
- } else if (right == ZR) { |
- bgez(left, l); |
- } else if (left == IMM) { |
- slti(AT, right, Immediate(cond.imm() + 1)); |
- bne(AT, ZR, l); |
- } else if (right == IMM) { |
- slti(AT, left, Immediate(cond.imm())); |
- beq(AT, ZR, l); |
- } else { |
- slt(AT, left, right); |
- beq(AT, ZR, l); |
- } |
- break; |
- } |
- case LT: { |
- if (left == ZR) { |
- bgtz(right, l); |
- } else if (right == ZR) { |
- bltz(left, l); |
- } else if (left == IMM) { |
- slti(AT, right, Immediate(cond.imm() + 1)); |
- beq(AT, ZR, l); |
- } else if (right == IMM) { |
- slti(AT, left, Immediate(cond.imm())); |
- bne(AT, ZR, l); |
- } else { |
- slt(AT, left, right); |
- bne(AT, ZR, l); |
- } |
- break; |
- } |
- case LE: { |
- if (left == ZR) { |
- bgez(right, l); |
- } else if (right == ZR) { |
- blez(left, l); |
- } else if (left == IMM) { |
- slti(AT, right, Immediate(cond.imm())); |
- beq(AT, ZR, l); |
- } else if (right == IMM) { |
- slti(AT, left, Immediate(cond.imm() + 1)); |
- bne(AT, ZR, l); |
- } else { |
- slt(AT, right, left); |
- beq(AT, ZR, l); |
- } |
- break; |
- } |
- case UGT: { |
- ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used. |
- if (left == ZR) { |
- // NV: Never branch. Fall through. |
- } else if (right == ZR) { |
- bne(left, ZR, l); |
- } else { |
- sltu(AT, right, left); |
- bne(AT, ZR, l); |
- } |
- break; |
- } |
- case UGE: { |
- ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used. |
- if (left == ZR) { |
- beq(right, ZR, l); |
- } else if (right == ZR) { |
- // AL: Always branch to l. |
- beq(ZR, ZR, l); |
- } else { |
- sltu(AT, left, right); |
- beq(AT, ZR, l); |
- } |
- break; |
- } |
- case ULT: { |
- ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used. |
- if (left == ZR) { |
- bne(right, ZR, l); |
- } else if (right == ZR) { |
- // NV: Never branch. Fall through. |
- } else { |
- sltu(AT, left, right); |
- bne(AT, ZR, l); |
- } |
- break; |
- } |
- case ULE: { |
- ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used. |
- if (left == ZR) { |
- // AL: Always branch to l. |
- beq(ZR, ZR, l); |
- } else if (right == ZR) { |
- beq(left, ZR, l); |
- } else { |
- sltu(AT, right, left); |
- beq(AT, ZR, l); |
- } |
- break; |
- } |
- default: |
- UNREACHABLE(); |
- } |
- } |
- |
- void BranchEqual(Register rd, Register rn, Label* l) { beq(rd, rn, l); } |
- |
- void BranchEqual(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- beq(rd, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- beq(rd, CMPRES2, l); |
- } |
- } |
- |
- void BranchEqual(Register rd, const Object& object, Label* l) { |
- ASSERT(!in_delay_slot_); |
- ASSERT(rd != CMPRES2); |
- LoadObject(CMPRES2, object); |
- beq(rd, CMPRES2, l); |
- } |
- |
- void BranchNotEqual(Register rd, Register rn, Label* l) { bne(rd, rn, l); } |
- |
- void BranchNotEqual(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- bne(rd, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- bne(rd, CMPRES2, l); |
- } |
- } |
- |
- void BranchNotEqual(Register rd, const Object& object, Label* l) { |
- ASSERT(!in_delay_slot_); |
- ASSERT(rd != CMPRES2); |
- LoadObject(CMPRES2, object); |
- bne(rd, CMPRES2, l); |
- } |
- |
- void BranchSignedGreater(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- slt(CMPRES2, rs, rd); // CMPRES2 = rd > rs ? 1 : 0. |
- bne(CMPRES2, ZR, l); |
- } |
- |
- void BranchSignedGreater(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- bgtz(rd, l); |
- } else { |
- if (Utils::IsInt(kImmBits, imm.value() + 1)) { |
- slti(CMPRES2, rd, Immediate(imm.value() + 1)); |
- beq(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchSignedGreater(rd, CMPRES2, l); |
- } |
- } |
- } |
- |
- void BranchUnsignedGreater(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- sltu(CMPRES2, rs, rd); |
- bne(CMPRES2, ZR, l); |
- } |
- |
- void BranchUnsignedGreater(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- BranchNotEqual(rd, Immediate(0), l); |
- } else { |
- if ((imm.value() != -1) && Utils::IsInt(kImmBits, imm.value() + 1)) { |
- sltiu(CMPRES2, rd, Immediate(imm.value() + 1)); |
- beq(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchUnsignedGreater(rd, CMPRES2, l); |
- } |
- } |
- } |
- |
- void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- slt(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0. |
- beq(CMPRES2, ZR, l); // If CMPRES2 = 0, then rd >= rs. |
- } |
- |
- void BranchSignedGreaterEqual(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- bgez(rd, l); |
- } else { |
- if (Utils::IsInt(kImmBits, imm.value())) { |
- slti(CMPRES2, rd, imm); |
- beq(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchSignedGreaterEqual(rd, CMPRES2, l); |
- } |
- } |
- } |
- |
- void BranchUnsignedGreaterEqual(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- sltu(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0. |
- beq(CMPRES2, ZR, l); |
- } |
- |
- void BranchUnsignedGreaterEqual(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- b(l); |
- } else { |
- if (Utils::IsInt(kImmBits, imm.value())) { |
- sltiu(CMPRES2, rd, imm); |
- beq(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchUnsignedGreaterEqual(rd, CMPRES2, l); |
- } |
- } |
- } |
- |
- void BranchSignedLess(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- BranchSignedGreater(rs, rd, l); |
- } |
- |
- void BranchSignedLess(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- bltz(rd, l); |
- } else { |
- if (Utils::IsInt(kImmBits, imm.value())) { |
- slti(CMPRES2, rd, imm); |
- bne(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchSignedGreater(CMPRES2, rd, l); |
- } |
- } |
- } |
- |
- void BranchUnsignedLess(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- BranchUnsignedGreater(rs, rd, l); |
- } |
- |
- void BranchUnsignedLess(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- // Never branch. Fall through. |
- } else { |
- if (Utils::IsInt(kImmBits, imm.value())) { |
- sltiu(CMPRES2, rd, imm); |
- bne(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchUnsignedGreater(CMPRES2, rd, l); |
- } |
- } |
- } |
- |
- void BranchSignedLessEqual(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- BranchSignedGreaterEqual(rs, rd, l); |
- } |
- |
- void BranchSignedLessEqual(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- blez(rd, l); |
- } else { |
- if (Utils::IsInt(kImmBits, imm.value() + 1)) { |
- slti(CMPRES2, rd, Immediate(imm.value() + 1)); |
- bne(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchSignedGreaterEqual(CMPRES2, rd, l); |
- } |
- } |
- } |
- |
- void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) { |
- ASSERT(!in_delay_slot_); |
- BranchUnsignedGreaterEqual(rs, rd, l); |
- } |
- |
- void BranchUnsignedLessEqual(Register rd, const Immediate& imm, Label* l) { |
- ASSERT(!in_delay_slot_); |
- if (imm.value() == 0) { |
- beq(rd, ZR, l); |
- } else { |
- if ((imm.value() != -1) && Utils::IsInt(kImmBits, imm.value() + 1)) { |
- sltiu(CMPRES2, rd, Immediate(imm.value() + 1)); |
- bne(CMPRES2, ZR, l); |
- } else { |
- ASSERT(rd != CMPRES2); |
- LoadImmediate(CMPRES2, imm.value()); |
- BranchUnsignedGreaterEqual(CMPRES2, rd, l); |
- } |
- } |
- } |
- |
- void Push(Register rt) { |
- ASSERT(!in_delay_slot_); |
- addiu(SP, SP, Immediate(-kWordSize)); |
- sw(rt, Address(SP)); |
- } |
- |
- void Pop(Register rt) { |
- ASSERT(!in_delay_slot_); |
- lw(rt, Address(SP)); |
- addiu(SP, SP, Immediate(kWordSize)); |
- } |
- |
- void Ret() { jr(RA); } |
- |
- void SmiTag(Register reg) { sll(reg, reg, kSmiTagSize); } |
- |
- void SmiTag(Register dst, Register src) { sll(dst, src, kSmiTagSize); } |
- |
- void SmiUntag(Register reg) { sra(reg, reg, kSmiTagSize); } |
- |
- void SmiUntag(Register dst, Register src) { sra(dst, src, kSmiTagSize); } |
- |
- void BranchIfNotSmi(Register reg, Label* label) { |
- andi(CMPRES1, reg, Immediate(kSmiTagMask)); |
- bne(CMPRES1, ZR, label); |
- } |
- |
- void BranchIfSmi(Register reg, Label* label) { |
- andi(CMPRES1, reg, Immediate(kSmiTagMask)); |
- beq(CMPRES1, ZR, label); |
- } |
- |
- void LoadFromOffset(Register reg, Register base, int32_t offset) { |
- ASSERT(!in_delay_slot_); |
- if (Utils::IsInt(kImmBits, offset)) { |
- lw(reg, Address(base, offset)); |
- } else { |
- LoadImmediate(TMP, offset); |
- addu(TMP, base, TMP); |
- lw(reg, Address(TMP, 0)); |
- } |
- } |
- |
- void LoadFieldFromOffset(Register reg, Register base, int32_t offset) { |
- LoadFromOffset(reg, base, offset - kHeapObjectTag); |
- } |
- |
- void StoreToOffset(Register reg, Register base, int32_t offset) { |
- ASSERT(!in_delay_slot_); |
- if (Utils::IsInt(kImmBits, offset)) { |
- sw(reg, Address(base, offset)); |
- } else { |
- LoadImmediate(TMP, offset); |
- addu(TMP, base, TMP); |
- sw(reg, Address(TMP, 0)); |
- } |
- } |
- |
- void StoreFieldToOffset(Register reg, Register base, int32_t offset) { |
- StoreToOffset(reg, base, offset - kHeapObjectTag); |
- } |
- |
- |
- void StoreDToOffset(DRegister reg, Register base, int32_t offset) { |
- ASSERT(!in_delay_slot_); |
- FRegister lo = static_cast<FRegister>(reg * 2); |
- FRegister hi = static_cast<FRegister>(reg * 2 + 1); |
- swc1(lo, Address(base, offset)); |
- swc1(hi, Address(base, offset + kWordSize)); |
- } |
- |
- void LoadDFromOffset(DRegister reg, Register base, int32_t offset) { |
- ASSERT(!in_delay_slot_); |
- FRegister lo = static_cast<FRegister>(reg * 2); |
- FRegister hi = static_cast<FRegister>(reg * 2 + 1); |
- lwc1(lo, Address(base, offset)); |
- lwc1(hi, Address(base, offset + kWordSize)); |
- } |
- |
- // dest gets the address of the following instruction. If temp is given, |
- // RA is preserved using it as a temporary. |
- void GetNextPC(Register dest, Register temp = kNoRegister); |
- |
- void ReserveAlignedFrameSpace(intptr_t frame_space); |
- |
- // Create a frame for calling into runtime that preserves all volatile |
- // registers. Frame's SP is guaranteed to be correctly aligned and |
- // frame_space bytes are reserved under it. |
- void EnterCallRuntimeFrame(intptr_t frame_space); |
- void LeaveCallRuntimeFrame(); |
- |
- void LoadObject(Register rd, const Object& object); |
- void LoadUniqueObject(Register rd, const Object& object); |
- void LoadFunctionFromCalleePool(Register dst, |
- const Function& function, |
- Register new_pp); |
- void LoadNativeEntry(Register rd, |
- const ExternalLabel* label, |
- Patchability patchable); |
- void PushObject(const Object& object); |
- |
- void LoadIsolate(Register result); |
- |
- void LoadClassId(Register result, Register object); |
- void LoadClassById(Register result, Register class_id); |
- void LoadClass(Register result, Register object); |
- void LoadClassIdMayBeSmi(Register result, Register object); |
- void LoadTaggedClassIdMayBeSmi(Register result, Register object); |
- |
- void StoreIntoObject(Register object, // Object we are storing into. |
- const Address& dest, // Where we are storing into. |
- Register value, // Value we are storing. |
- bool can_value_be_smi = true); |
- void StoreIntoObjectOffset(Register object, |
- int32_t offset, |
- Register value, |
- bool can_value_be_smi = true); |
- |
- void StoreIntoObjectNoBarrier(Register object, |
- const Address& dest, |
- Register value); |
- void StoreIntoObjectNoBarrierOffset(Register object, |
- int32_t offset, |
- Register value); |
- void StoreIntoObjectNoBarrier(Register object, |
- const Address& dest, |
- const Object& value); |
- void StoreIntoObjectNoBarrierOffset(Register object, |
- int32_t offset, |
- const Object& value); |
- |
- void CallRuntime(const RuntimeEntry& entry, intptr_t argument_count); |
- |
- // Set up a Dart frame on entry with a frame pointer and PC information to |
- // enable easy access to the RawInstruction object of code corresponding |
- // to this frame. |
- void EnterDartFrame(intptr_t frame_size); |
- void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP); |
- void LeaveDartFrameAndReturn(Register ra = RA); |
- |
- // Set up a Dart frame for a function compiled for on-stack replacement. |
- // The frame layout is a normal Dart frame, but the frame is partially set |
- // up on entry (it is the frame of the unoptimized code). |
- void EnterOsrFrame(intptr_t extra_size); |
- |
- Address ElementAddressForIntIndex(bool is_external, |
- intptr_t cid, |
- intptr_t index_scale, |
- Register array, |
- intptr_t index) const; |
- void LoadElementAddressForIntIndex(Register address, |
- bool is_external, |
- intptr_t cid, |
- intptr_t index_scale, |
- Register array, |
- intptr_t index); |
- Address ElementAddressForRegIndex(bool is_load, |
- bool is_external, |
- intptr_t cid, |
- intptr_t index_scale, |
- Register array, |
- Register index); |
- void LoadElementAddressForRegIndex(Register address, |
- bool is_load, |
- bool is_external, |
- intptr_t cid, |
- intptr_t index_scale, |
- Register array, |
- Register index); |
- |
- void LoadHalfWordUnaligned(Register dst, Register addr, Register tmp); |
- void LoadHalfWordUnsignedUnaligned(Register dst, Register addr, Register tmp); |
- void StoreHalfWordUnaligned(Register src, Register addr, Register tmp); |
- void LoadWordUnaligned(Register dst, Register addr, Register tmp); |
- void StoreWordUnaligned(Register src, Register addr, Register tmp); |
- |
- static Address VMTagAddress() { |
- return Address(THR, Thread::vm_tag_offset()); |
- } |
- |
- // On some other platforms, we draw a distinction between safe and unsafe |
- // smis. |
- static bool IsSafe(const Object& object) { return true; } |
- static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } |
- |
- bool constant_pool_allowed() const { return constant_pool_allowed_; } |
- void set_constant_pool_allowed(bool b) { constant_pool_allowed_ = b; } |
- |
- private: |
- AssemblerBuffer buffer_; |
- ObjectPoolWrapper object_pool_wrapper_; |
- |
- intptr_t prologue_offset_; |
- bool has_single_entry_point_; |
- bool use_far_branches_; |
- bool delay_slot_available_; |
- bool in_delay_slot_; |
- |
- class CodeComment : public ZoneAllocated { |
- public: |
- CodeComment(intptr_t pc_offset, const String& comment) |
- : pc_offset_(pc_offset), comment_(comment) {} |
- |
- intptr_t pc_offset() const { return pc_offset_; } |
- const String& comment() const { return comment_; } |
- |
- private: |
- intptr_t pc_offset_; |
- const String& comment_; |
- |
- DISALLOW_COPY_AND_ASSIGN(CodeComment); |
- }; |
- |
- GrowableArray<CodeComment*> comments_; |
- |
- bool constant_pool_allowed_; |
- |
- void BranchLink(const ExternalLabel* label); |
- void BranchLink(const Code& code, Patchability patchable); |
- |
- bool CanLoadFromObjectPool(const Object& object) const; |
- |
- void LoadWordFromPoolOffset(Register rd, int32_t offset, Register pp = PP); |
- void LoadObjectHelper(Register rd, const Object& object, bool is_unique); |
- |
- void Emit(int32_t value) { |
- // Emitting an instruction clears the delay slot state. |
- in_delay_slot_ = false; |
- delay_slot_available_ = false; |
- AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
- buffer_.Emit<int32_t>(value); |
- } |
- |
- // Encode CPU instructions according to the types specified in |
- // Figures 4-1, 4-2 and 4-3 in VolI-A. |
- void EmitIType(Opcode opcode, Register rs, Register rt, uint16_t imm) { |
- Emit(opcode << kOpcodeShift | rs << kRsShift | rt << kRtShift | imm); |
- } |
- |
- void EmitLoadStore(Opcode opcode, Register rt, const Address& addr) { |
- Emit(opcode << kOpcodeShift | rt << kRtShift | addr.encoding()); |
- } |
- |
- void EmitFpuLoadStore(Opcode opcode, FRegister ft, const Address& addr) { |
- Emit(opcode << kOpcodeShift | ft << kFtShift | addr.encoding()); |
- } |
- |
- void EmitRegImmType(Opcode opcode, Register rs, RtRegImm code, uint16_t imm) { |
- Emit(opcode << kOpcodeShift | rs << kRsShift | code << kRtShift | imm); |
- } |
- |
- void EmitJType(Opcode opcode, uint32_t destination) { UNIMPLEMENTED(); } |
- |
- void EmitRType(Opcode opcode, |
- Register rs, |
- Register rt, |
- Register rd, |
- int sa, |
- SpecialFunction func) { |
- ASSERT(Utils::IsUint(5, sa)); |
- Emit(opcode << kOpcodeShift | rs << kRsShift | rt << kRtShift | |
- rd << kRdShift | sa << kSaShift | func << kFunctionShift); |
- } |
- |
- void EmitFpuRType(Opcode opcode, |
- Format fmt, |
- FRegister ft, |
- FRegister fs, |
- FRegister fd, |
- Cop1Function func) { |
- Emit(opcode << kOpcodeShift | fmt << kFmtShift | ft << kFtShift | |
- fs << kFsShift | fd << kFdShift | func << kCop1FnShift); |
- } |
- |
- int32_t EncodeBranchOffset(int32_t offset, int32_t instr); |
- |
- void EmitFarJump(int32_t offset, bool link); |
- void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset); |
- void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset); |
- void EmitFarFpuBranch(bool kind, int32_t offset); |
- void EmitBranch(Opcode b, Register rs, Register rt, Label* label); |
- void EmitRegImmBranch(RtRegImm b, Register rs, Label* label); |
- void EmitFpuBranch(bool kind, Label* label); |
- |
- void EmitBranchDelayNop() { |
- Emit(Instr::kNopInstruction); // Branch delay NOP. |
- delay_slot_available_ = true; |
- } |
- |
- void StoreIntoObjectFilter(Register object, Register value, Label* no_update); |
- |
- // Shorter filtering sequence that assumes that value is not a smi. |
- void StoreIntoObjectFilterNoSmi(Register object, |
- Register value, |
- Label* no_update); |
- |
- DISALLOW_ALLOCATION(); |
- DISALLOW_COPY_AND_ASSIGN(Assembler); |
-}; |
- |
-} // namespace dart |
- |
-#endif // RUNTIME_VM_ASSEMBLER_MIPS_H_ |