Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Unified Diff: runtime/vm/assembler_mips.h

Issue 2858623002: Remove MIPS support (Closed)
Patch Set: Merge and cleanup Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/assembler_ia32.h ('k') | runtime/vm/assembler_mips.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_
« no previous file with comments | « runtime/vm/assembler_ia32.h ('k') | runtime/vm/assembler_mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698