diff options
Diffstat (limited to 'runtime/oat/utils/mips/assembler_mips.h')
-rw-r--r-- | runtime/oat/utils/mips/assembler_mips.h | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/runtime/oat/utils/mips/assembler_mips.h b/runtime/oat/utils/mips/assembler_mips.h new file mode 100644 index 0000000000..02759e4efb --- /dev/null +++ b/runtime/oat/utils/mips/assembler_mips.h @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ +#define ART_SRC_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ + +#include <vector> + +#include "base/macros.h" +#include "constants_mips.h" +#include "globals.h" +#include "managed_register_mips.h" +#include "oat/utils/assembler.h" +#include "offsets.h" +#include "utils.h" + +namespace art { +namespace mips { +#if 0 +class Operand { + public: + uint8_t mod() const { + return (encoding_at(0) >> 6) & 3; + } + + Register rm() const { + return static_cast<Register>(encoding_at(0) & 7); + } + + ScaleFactor scale() const { + return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); + } + + Register index() const { + return static_cast<Register>((encoding_at(1) >> 3) & 7); + } + + Register base() const { + return static_cast<Register>(encoding_at(1) & 7); + } + + int8_t disp8() const { + CHECK_GE(length_, 2); + return static_cast<int8_t>(encoding_[length_ - 1]); + } + + int32_t disp32() const { + CHECK_GE(length_, 5); + int32_t value; + memcpy(&value, &encoding_[length_ - 4], sizeof(value)); + return value; + } + + bool IsRegister(Register reg) const { + return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. + && ((encoding_[0] & 0x07) == reg); // Register codes match. + } + + protected: + // Operand can be sub classed (e.g: Address). + Operand() : length_(0) { } + + void SetModRM(int mod, Register rm) { + CHECK_EQ(mod & ~3, 0); + encoding_[0] = (mod << 6) | rm; + length_ = 1; + } + + void SetSIB(ScaleFactor scale, Register index, Register base) { + CHECK_EQ(length_, 1); + CHECK_EQ(scale & ~3, 0); + encoding_[1] = (scale << 6) | (index << 3) | base; + length_ = 2; + } + + void SetDisp8(int8_t disp) { + CHECK(length_ == 1 || length_ == 2); + encoding_[length_++] = static_cast<uint8_t>(disp); + } + + void SetDisp32(int32_t disp) { + CHECK(length_ == 1 || length_ == 2); + int disp_size = sizeof(disp); + memmove(&encoding_[length_], &disp, disp_size); + length_ += disp_size; + } + + private: + byte length_; + byte encoding_[6]; + byte padding_; + + explicit Operand(Register reg) { SetModRM(3, reg); } + + // Get the operand encoding byte at the given index. + uint8_t encoding_at(int index) const { + CHECK_GE(index, 0); + CHECK_LT(index, length_); + return encoding_[index]; + } + + friend class MipsAssembler; + + // TODO: Remove the #if when Mac OS build server no longer uses GCC 4.2.*. +#if GCC_VERSION >= 40300 + DISALLOW_COPY_AND_ASSIGN(Operand); +#endif +}; + + +class Address : public Operand { + public: + Address(Register base, int32_t disp) { + Init(base, disp); + } + + Address(Register base, Offset disp) { + Init(base, disp.Int32Value()); + } + + Address(Register base, FrameOffset disp) { + CHECK_EQ(base, ESP); + Init(ESP, disp.Int32Value()); + } + + Address(Register base, MemberOffset disp) { + Init(base, disp.Int32Value()); + } + + void Init(Register base, int32_t disp) { + if (disp == 0 && base != EBP) { + SetModRM(0, base); + if (base == ESP) SetSIB(TIMES_1, ESP, base); + } else if (disp >= -128 && disp <= 127) { + SetModRM(1, base); + if (base == ESP) SetSIB(TIMES_1, ESP, base); + SetDisp8(disp); + } else { + SetModRM(2, base); + if (base == ESP) SetSIB(TIMES_1, ESP, base); + SetDisp32(disp); + } + } + + + Address(Register index, ScaleFactor scale, int32_t disp) { + CHECK_NE(index, ESP); // Illegal addressing mode. + SetModRM(0, ESP); + SetSIB(scale, index, EBP); + SetDisp32(disp); + } + + Address(Register base, Register index, ScaleFactor scale, int32_t disp) { + CHECK_NE(index, ESP); // Illegal addressing mode. + if (disp == 0 && base != EBP) { + SetModRM(0, ESP); + SetSIB(scale, index, base); + } else if (disp >= -128 && disp <= 127) { + SetModRM(1, ESP); + SetSIB(scale, index, base); + SetDisp8(disp); + } else { + SetModRM(2, ESP); + SetSIB(scale, index, base); + SetDisp32(disp); + } + } + + static Address Absolute(uword addr) { + Address result; + result.SetModRM(0, EBP); + result.SetDisp32(addr); + return result; + } + + static Address Absolute(ThreadOffset addr) { + return Absolute(addr.Int32Value()); + } + + private: + Address() {} + + // TODO: Remove the #if when Mac OS build server no longer uses GCC 4.2.*. +#if GCC_VERSION >= 40300 + DISALLOW_COPY_AND_ASSIGN(Address); +#endif +}; + +#endif + +enum LoadOperandType { + kLoadSignedByte, + kLoadUnsignedByte, + kLoadSignedHalfword, + kLoadUnsignedHalfword, + kLoadWord, + kLoadWordPair, + kLoadSWord, + kLoadDWord +}; + +enum StoreOperandType { + kStoreByte, + kStoreHalfword, + kStoreWord, + kStoreWordPair, + kStoreSWord, + kStoreDWord +}; + +class MipsAssembler : public Assembler { + public: + MipsAssembler() {} + virtual ~MipsAssembler() {} + + // Emit Machine Instructions. + void Add(Register rd, Register rs, Register rt); + void Addu(Register rd, Register rs, Register rt); + void Addi(Register rt, Register rs, uint16_t imm16); + void Addiu(Register rt, Register rs, uint16_t imm16); + void Sub(Register rd, Register rs, Register rt); + void Subu(Register rd, Register rs, Register rt); + void Mult(Register rs, Register rt); + void Multu(Register rs, Register rt); + void Div(Register rs, Register rt); + void Divu(Register rs, Register rt); + + void And(Register rd, Register rs, Register rt); + void Andi(Register rt, Register rs, uint16_t imm16); + void Or(Register rd, Register rs, Register rt); + void Ori(Register rt, Register rs, uint16_t imm16); + void Xor(Register rd, Register rs, Register rt); + void Xori(Register rt, Register rs, uint16_t imm16); + void Nor(Register rd, Register rs, Register rt); + + void Sll(Register rd, Register rs, int shamt); + void Srl(Register rd, Register rs, int shamt); + void Sra(Register rd, Register rs, int shamt); + void Sllv(Register rd, Register rs, Register rt); + void Srlv(Register rd, Register rs, Register rt); + void Srav(Register rd, Register rs, Register rt); + + void Lb(Register rt, Register rs, uint16_t imm16); + void Lh(Register rt, Register rs, uint16_t imm16); + void Lw(Register rt, Register rs, uint16_t imm16); + void Lbu(Register rt, Register rs, uint16_t imm16); + void Lhu(Register rt, Register rs, uint16_t imm16); + void Lui(Register rt, uint16_t imm16); + void Mfhi(Register rd); + void Mflo(Register rd); + + void Sb(Register rt, Register rs, uint16_t imm16); + void Sh(Register rt, Register rs, uint16_t imm16); + void Sw(Register rt, Register rs, uint16_t imm16); + + void Slt(Register rd, Register rs, Register rt); + void Sltu(Register rd, Register rs, Register rt); + void Slti(Register rt, Register rs, uint16_t imm16); + void Sltiu(Register rt, Register rs, uint16_t imm16); + + void Beq(Register rt, Register rs, uint16_t imm16); + void Bne(Register rt, Register rs, uint16_t imm16); + void J(uint32_t address); + void Jal(uint32_t address); + void Jr(Register rs); + void Jalr(Register rs); + + void AddS(FRegister fd, FRegister fs, FRegister ft); + void SubS(FRegister fd, FRegister fs, FRegister ft); + void MulS(FRegister fd, FRegister fs, FRegister ft); + void DivS(FRegister fd, FRegister fs, FRegister ft); + void AddD(DRegister fd, DRegister fs, DRegister ft); + void SubD(DRegister fd, DRegister fs, DRegister ft); + void MulD(DRegister fd, DRegister fs, DRegister ft); + void DivD(DRegister fd, DRegister fs, DRegister ft); + void MovS(FRegister fd, FRegister fs); + void MovD(DRegister fd, DRegister fs); + + void Mfc1(Register rt, FRegister fs); + void Mtc1(FRegister ft, Register rs); + void Lwc1(FRegister ft, Register rs, uint16_t imm16); + void Ldc1(DRegister ft, Register rs, uint16_t imm16); + void Swc1(FRegister ft, Register rs, uint16_t imm16); + void Sdc1(DRegister ft, Register rs, uint16_t imm16); + + void Break(); + void Nop(); + void Move(Register rt, Register rs); + void Clear(Register rt); + void Not(Register rt, Register rs); + void Mul(Register rd, Register rs, Register rt); + void Div(Register rd, Register rs, Register rt); + void Rem(Register rd, Register rs, Register rt); + + void AddConstant(Register rt, Register rs, int32_t value); + void LoadImmediate(Register rt, int32_t value); + + void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size); + void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset); + void LoadSFromOffset(FRegister reg, Register base, int32_t offset); + void LoadDFromOffset(DRegister reg, Register base, int32_t offset); + void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset); + void StoreFToOffset(FRegister reg, Register base, int32_t offset); + void StoreDToOffset(DRegister reg, Register base, int32_t offset); + +#if 0 + MipsAssembler* lock(); + + void mfence(); + + MipsAssembler* fs(); + + // + // Macros for High-level operations. + // + + void AddImmediate(Register reg, const Immediate& imm); + + void LoadDoubleConstant(XmmRegister dst, double value); + + void DoubleNegate(XmmRegister d); + void FloatNegate(XmmRegister f); + + void DoubleAbs(XmmRegister reg); + + void LockCmpxchgl(const Address& address, Register reg) { + lock()->cmpxchgl(address, reg); + } + + // + // Misc. functionality + // + int PreferredLoopAlignment() { return 16; } + void Align(int alignment, int offset); + + // Debugging and bringup support. + void Stop(const char* message); +#endif + + // Emit data (e.g. encoded instruction or immediate) to the instruction stream. + void Emit(int32_t value); + void EmitBranch(Register rt, Register rs, Label* label, bool equal); + void EmitJump(Label* label, bool link); + void Bind(Label* label, bool is_jump); + + // + // Overridden common assembler high-level functionality + // + + // Emit code that will create an activation on the stack + virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg, + const std::vector<ManagedRegister>& callee_save_regs, + const std::vector<ManagedRegister>& entry_spills); + + // Emit code that will remove an activation from the stack + virtual void RemoveFrame(size_t frame_size, + const std::vector<ManagedRegister>& callee_save_regs); + + virtual void IncreaseFrameSize(size_t adjust); + virtual void DecreaseFrameSize(size_t adjust); + + // Store routines + virtual void Store(FrameOffset offs, ManagedRegister msrc, size_t size); + virtual void StoreRef(FrameOffset dest, ManagedRegister msrc); + virtual void StoreRawPtr(FrameOffset dest, ManagedRegister msrc); + + virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, + ManagedRegister mscratch); + + virtual void StoreImmediateToThread(ThreadOffset dest, uint32_t imm, + ManagedRegister mscratch); + + virtual void StoreStackOffsetToThread(ThreadOffset thr_offs, + FrameOffset fr_offs, + ManagedRegister mscratch); + + virtual void StoreStackPointerToThread(ThreadOffset thr_offs); + + virtual void StoreSpanning(FrameOffset dest, ManagedRegister msrc, + FrameOffset in_off, ManagedRegister mscratch); + + // Load routines + virtual void Load(ManagedRegister mdest, FrameOffset src, size_t size); + + virtual void Load(ManagedRegister mdest, ThreadOffset src, size_t size); + + virtual void LoadRef(ManagedRegister dest, FrameOffset src); + + virtual void LoadRef(ManagedRegister mdest, ManagedRegister base, + MemberOffset offs); + + virtual void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, + Offset offs); + + virtual void LoadRawPtrFromThread(ManagedRegister mdest, + ThreadOffset offs); + + // Copying routines + virtual void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size); + + virtual void CopyRawPtrFromThread(FrameOffset fr_offs, ThreadOffset thr_offs, + ManagedRegister mscratch); + + virtual void CopyRawPtrToThread(ThreadOffset thr_offs, FrameOffset fr_offs, + ManagedRegister mscratch); + + virtual void CopyRef(FrameOffset dest, FrameOffset src, + ManagedRegister mscratch); + + virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size); + + virtual void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, + ManagedRegister mscratch, size_t size); + + virtual void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, + ManagedRegister mscratch, size_t size); + + virtual void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, + ManagedRegister mscratch, size_t size); + + virtual void Copy(ManagedRegister dest, Offset dest_offset, + ManagedRegister src, Offset src_offset, + ManagedRegister mscratch, size_t size); + + virtual void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, + ManagedRegister mscratch, size_t size); + + virtual void MemoryBarrier(ManagedRegister); + + // Sign extension + virtual void SignExtend(ManagedRegister mreg, size_t size); + + // Zero extension + virtual void ZeroExtend(ManagedRegister mreg, size_t size); + + // Exploit fast access in managed code to Thread::Current() + virtual void GetCurrentThread(ManagedRegister tr); + virtual void GetCurrentThread(FrameOffset dest_offset, + ManagedRegister mscratch); + + // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the + // value is null and null_allowed. in_reg holds a possibly stale reference + // that can be used to avoid loading the SIRT entry to see if the value is + // NULL. + virtual void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset, + ManagedRegister in_reg, bool null_allowed); + + // Set up out_off to hold a Object** into the SIRT, or to be NULL if the + // value is null and null_allowed. + virtual void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset, + ManagedRegister mscratch, bool null_allowed); + + // src holds a SIRT entry (Object**) load this into dst + virtual void LoadReferenceFromSirt(ManagedRegister dst, + ManagedRegister src); + + // Heap::VerifyObject on src. In some cases (such as a reference to this) we + // know that src may not be null. + virtual void VerifyObject(ManagedRegister src, bool could_be_null); + virtual void VerifyObject(FrameOffset src, bool could_be_null); + + // Call to address held at [base+offset] + virtual void Call(ManagedRegister base, Offset offset, + ManagedRegister mscratch); + virtual void Call(FrameOffset base, Offset offset, + ManagedRegister mscratch); + virtual void Call(ThreadOffset offset, ManagedRegister mscratch); + + // Generate code to check if Thread::Current()->exception_ is non-null + // and branch to a ExceptionSlowPath if it is. + virtual void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust); + + private: + void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct); + void EmitI(int opcode, Register rs, Register rt, uint16_t imm); + void EmitJ(int opcode, int address); + void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct); + void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm); + + int32_t EncodeBranchOffset(int offset, int32_t inst, bool is_jump); + int DecodeBranchOffset(int32_t inst, bool is_jump); + + DISALLOW_COPY_AND_ASSIGN(MipsAssembler); +}; + +// Slowpath entered when Thread::Current()->_exception is non-null +class MipsExceptionSlowPath : public SlowPath { + public: + explicit MipsExceptionSlowPath(MipsManagedRegister scratch, size_t stack_adjust) + : scratch_(scratch), stack_adjust_(stack_adjust) {} + virtual void Emit(Assembler *sp_asm); + private: + const MipsManagedRegister scratch_; + const size_t stack_adjust_; +}; + +} // namespace mips +} // namespace art + +#endif // ART_SRC_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ |