| /* | 
 |  * 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_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ | 
 | #define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "constants_arm.h" | 
 | #include "utils/arm/managed_register_arm.h" | 
 | #include "utils/assembler.h" | 
 | #include "offsets.h" | 
 | #include "utils.h" | 
 |  | 
 | namespace art { | 
 | namespace arm { | 
 |  | 
 | // Encodes Addressing Mode 1 - Data-processing operands defined in Section 5.1. | 
 | class ShifterOperand { | 
 |  public: | 
 |   // Data-processing operands - Uninitialized | 
 |   ShifterOperand() { | 
 |     type_ = -1; | 
 |   } | 
 |  | 
 |   // Data-processing operands - Immediate | 
 |   explicit ShifterOperand(uint32_t immediate) { | 
 |     CHECK(immediate < (1 << kImmed8Bits)); | 
 |     type_ = 1; | 
 |     encoding_ = immediate; | 
 |   } | 
 |  | 
 |   // Data-processing operands - Rotated immediate | 
 |   ShifterOperand(uint32_t rotate, uint32_t immed8) { | 
 |     CHECK((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits))); | 
 |     type_ = 1; | 
 |     encoding_ = (rotate << kRotateShift) | (immed8 << kImmed8Shift); | 
 |   } | 
 |  | 
 |   // Data-processing operands - Register | 
 |   explicit ShifterOperand(Register rm) { | 
 |     type_ = 0; | 
 |     encoding_ = static_cast<uint32_t>(rm); | 
 |   } | 
 |  | 
 |   // Data-processing operands - Logical shift/rotate by immediate | 
 |   ShifterOperand(Register rm, Shift shift, uint32_t shift_imm) { | 
 |     CHECK(shift_imm < (1 << kShiftImmBits)); | 
 |     type_ = 0; | 
 |     encoding_ = shift_imm << kShiftImmShift | | 
 |                 static_cast<uint32_t>(shift) << kShiftShift | | 
 |                 static_cast<uint32_t>(rm); | 
 |   } | 
 |  | 
 |   // Data-processing operands - Logical shift/rotate by register | 
 |   ShifterOperand(Register rm, Shift shift, Register rs) { | 
 |     type_ = 0; | 
 |     encoding_ = static_cast<uint32_t>(rs) << kShiftRegisterShift | | 
 |                 static_cast<uint32_t>(shift) << kShiftShift | (1 << 4) | | 
 |                 static_cast<uint32_t>(rm); | 
 |   } | 
 |  | 
 |   static bool CanHold(uint32_t immediate, ShifterOperand* shifter_op) { | 
 |     // Avoid the more expensive test for frequent small immediate values. | 
 |     if (immediate < (1 << kImmed8Bits)) { | 
 |       shifter_op->type_ = 1; | 
 |       shifter_op->encoding_ = (0 << kRotateShift) | (immediate << kImmed8Shift); | 
 |       return true; | 
 |     } | 
 |     // Note that immediate must be unsigned for the test to work correctly. | 
 |     for (int rot = 0; rot < 16; rot++) { | 
 |       uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot)); | 
 |       if (imm8 < (1 << kImmed8Bits)) { | 
 |         shifter_op->type_ = 1; | 
 |         shifter_op->encoding_ = (rot << kRotateShift) | (imm8 << kImmed8Shift); | 
 |         return true; | 
 |       } | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |  private: | 
 |   bool is_valid() const { return (type_ == 0) || (type_ == 1); } | 
 |  | 
 |   uint32_t type() const { | 
 |     CHECK(is_valid()); | 
 |     return type_; | 
 |   } | 
 |  | 
 |   uint32_t encoding() const { | 
 |     CHECK(is_valid()); | 
 |     return encoding_; | 
 |   } | 
 |  | 
 |   uint32_t type_;  // Encodes the type field (bits 27-25) in the instruction. | 
 |   uint32_t encoding_; | 
 |  | 
 |   friend class ArmAssembler; | 
 | #ifdef SOURCE_ASSEMBLER_SUPPORT | 
 |   friend class BinaryAssembler; | 
 | #endif | 
 | }; | 
 |  | 
 |  | 
 | enum LoadOperandType { | 
 |   kLoadSignedByte, | 
 |   kLoadUnsignedByte, | 
 |   kLoadSignedHalfword, | 
 |   kLoadUnsignedHalfword, | 
 |   kLoadWord, | 
 |   kLoadWordPair, | 
 |   kLoadSWord, | 
 |   kLoadDWord | 
 | }; | 
 |  | 
 |  | 
 | enum StoreOperandType { | 
 |   kStoreByte, | 
 |   kStoreHalfword, | 
 |   kStoreWord, | 
 |   kStoreWordPair, | 
 |   kStoreSWord, | 
 |   kStoreDWord | 
 | }; | 
 |  | 
 |  | 
 | // Load/store multiple addressing mode. | 
 | enum BlockAddressMode { | 
 |   // bit encoding P U W | 
 |   DA           = (0|0|0) << 21,  // decrement after | 
 |   IA           = (0|4|0) << 21,  // increment after | 
 |   DB           = (8|0|0) << 21,  // decrement before | 
 |   IB           = (8|4|0) << 21,  // increment before | 
 |   DA_W         = (0|0|1) << 21,  // decrement after with writeback to base | 
 |   IA_W         = (0|4|1) << 21,  // increment after with writeback to base | 
 |   DB_W         = (8|0|1) << 21,  // decrement before with writeback to base | 
 |   IB_W         = (8|4|1) << 21   // increment before with writeback to base | 
 | }; | 
 |  | 
 |  | 
 | class Address { | 
 |  public: | 
 |   // Memory operand addressing mode | 
 |   enum Mode { | 
 |     // bit encoding P U W | 
 |     Offset       = (8|4|0) << 21,  // offset (w/o writeback to base) | 
 |     PreIndex     = (8|4|1) << 21,  // pre-indexed addressing with writeback | 
 |     PostIndex    = (0|4|0) << 21,  // post-indexed addressing with writeback | 
 |     NegOffset    = (8|0|0) << 21,  // negative offset (w/o writeback to base) | 
 |     NegPreIndex  = (8|0|1) << 21,  // negative pre-indexed with writeback | 
 |     NegPostIndex = (0|0|0) << 21   // negative post-indexed with writeback | 
 |   }; | 
 |  | 
 |   explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) { | 
 |     CHECK(IsAbsoluteUint(12, offset)); | 
 |     if (offset < 0) { | 
 |       encoding_ = (am ^ (1 << kUShift)) | -offset;  // Flip U to adjust sign. | 
 |     } else { | 
 |       encoding_ = am | offset; | 
 |     } | 
 |     encoding_ |= static_cast<uint32_t>(rn) << kRnShift; | 
 |   } | 
 |  | 
 |   static bool CanHoldLoadOffset(LoadOperandType type, int offset); | 
 |   static bool CanHoldStoreOffset(StoreOperandType type, int offset); | 
 |  | 
 |  private: | 
 |   uint32_t encoding() const { return encoding_; } | 
 |  | 
 |   // Encoding for addressing mode 3. | 
 |   uint32_t encoding3() const { | 
 |     const uint32_t offset_mask = (1 << 12) - 1; | 
 |     uint32_t offset = encoding_ & offset_mask; | 
 |     CHECK_LT(offset, 256u); | 
 |     return (encoding_ & ~offset_mask) | ((offset & 0xf0) << 4) | (offset & 0xf); | 
 |   } | 
 |  | 
 |   // Encoding for vfp load/store addressing. | 
 |   uint32_t vencoding() const { | 
 |     const uint32_t offset_mask = (1 << 12) - 1; | 
 |     uint32_t offset = encoding_ & offset_mask; | 
 |     CHECK(IsAbsoluteUint(10, offset));  // In the range -1020 to +1020. | 
 |     CHECK_ALIGNED(offset, 2);  // Multiple of 4. | 
 |     int mode = encoding_ & ((8|4|1) << 21); | 
 |     CHECK((mode == Offset) || (mode == NegOffset)); | 
 |     uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2); | 
 |     if (mode == Offset) { | 
 |       vencoding |= 1 << 23; | 
 |     } | 
 |     return vencoding; | 
 |   } | 
 |  | 
 |   uint32_t encoding_; | 
 |  | 
 |   friend class ArmAssembler; | 
 | }; | 
 |  | 
 |  | 
 | class ArmAssembler : public Assembler { | 
 |  public: | 
 |   ArmAssembler() {} | 
 |   virtual ~ArmAssembler() {} | 
 |  | 
 |   // Data-processing instructions. | 
 |   void and_(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void eor(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void sub(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |   void subs(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void rsb(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |   void rsbs(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void add(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void adds(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void adc(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void sbc(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void rsc(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void tst(Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void teq(Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void cmp(Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void cmn(Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void orr(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |   void orrs(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void mov(Register rd, ShifterOperand so, Condition cond = AL); | 
 |   void movs(Register rd, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void bic(Register rd, Register rn, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   void mvn(Register rd, ShifterOperand so, Condition cond = AL); | 
 |   void mvns(Register rd, ShifterOperand so, Condition cond = AL); | 
 |  | 
 |   // Miscellaneous data-processing instructions. | 
 |   void clz(Register rd, Register rm, Condition cond = AL); | 
 |   void movw(Register rd, uint16_t imm16, Condition cond = AL); | 
 |   void movt(Register rd, uint16_t imm16, Condition cond = AL); | 
 |  | 
 |   // Multiply instructions. | 
 |   void mul(Register rd, Register rn, Register rm, Condition cond = AL); | 
 |   void mla(Register rd, Register rn, Register rm, Register ra, | 
 |            Condition cond = AL); | 
 |   void mls(Register rd, Register rn, Register rm, Register ra, | 
 |            Condition cond = AL); | 
 |   void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, | 
 |              Condition cond = AL); | 
 |  | 
 |   // Load/store instructions. | 
 |   void ldr(Register rd, Address ad, Condition cond = AL); | 
 |   void str(Register rd, Address ad, Condition cond = AL); | 
 |  | 
 |   void ldrb(Register rd, Address ad, Condition cond = AL); | 
 |   void strb(Register rd, Address ad, Condition cond = AL); | 
 |  | 
 |   void ldrh(Register rd, Address ad, Condition cond = AL); | 
 |   void strh(Register rd, Address ad, Condition cond = AL); | 
 |  | 
 |   void ldrsb(Register rd, Address ad, Condition cond = AL); | 
 |   void ldrsh(Register rd, Address ad, Condition cond = AL); | 
 |  | 
 |   void ldrd(Register rd, Address ad, Condition cond = AL); | 
 |   void strd(Register rd, Address ad, Condition cond = AL); | 
 |  | 
 |   void ldm(BlockAddressMode am, Register base, | 
 |            RegList regs, Condition cond = AL); | 
 |   void stm(BlockAddressMode am, Register base, | 
 |            RegList regs, Condition cond = AL); | 
 |  | 
 |   void ldrex(Register rd, Register rn, Condition cond = AL); | 
 |   void strex(Register rd, Register rt, Register rn, Condition cond = AL); | 
 |  | 
 |   // Miscellaneous instructions. | 
 |   void clrex(); | 
 |   void nop(Condition cond = AL); | 
 |  | 
 |   // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. | 
 |   void bkpt(uint16_t imm16); | 
 |   void svc(uint32_t imm24); | 
 |  | 
 |   // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). | 
 |   void vmovsr(SRegister sn, Register rt, Condition cond = AL); | 
 |   void vmovrs(Register rt, SRegister sn, Condition cond = AL); | 
 |   void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL); | 
 |   void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL); | 
 |   void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL); | 
 |   void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL); | 
 |   void vmovs(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vmovd(DRegister dd, DRegister dm, Condition cond = AL); | 
 |  | 
 |   // Returns false if the immediate cannot be encoded. | 
 |   bool vmovs(SRegister sd, float s_imm, Condition cond = AL); | 
 |   bool vmovd(DRegister dd, double d_imm, Condition cond = AL); | 
 |  | 
 |   void vldrs(SRegister sd, Address ad, Condition cond = AL); | 
 |   void vstrs(SRegister sd, Address ad, Condition cond = AL); | 
 |   void vldrd(DRegister dd, Address ad, Condition cond = AL); | 
 |   void vstrd(DRegister dd, Address ad, Condition cond = AL); | 
 |  | 
 |   void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | 
 |   void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | 
 |   void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | 
 |   void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | 
 |   void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | 
 |   void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | 
 |   void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | 
 |   void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | 
 |   void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | 
 |   void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | 
 |   void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); | 
 |   void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); | 
 |  | 
 |   void vabss(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vabsd(DRegister dd, DRegister dm, Condition cond = AL); | 
 |   void vnegs(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vnegd(DRegister dd, DRegister dm, Condition cond = AL); | 
 |   void vsqrts(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL); | 
 |  | 
 |   void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL); | 
 |   void vcvtds(DRegister dd, SRegister sm, Condition cond = AL); | 
 |   void vcvtis(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vcvtid(SRegister sd, DRegister dm, Condition cond = AL); | 
 |   void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL); | 
 |   void vcvtus(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vcvtud(SRegister sd, DRegister dm, Condition cond = AL); | 
 |   void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL); | 
 |  | 
 |   void vcmps(SRegister sd, SRegister sm, Condition cond = AL); | 
 |   void vcmpd(DRegister dd, DRegister dm, Condition cond = AL); | 
 |   void vcmpsz(SRegister sd, Condition cond = AL); | 
 |   void vcmpdz(DRegister dd, Condition cond = AL); | 
 |   void vmstat(Condition cond = AL);  // VMRS APSR_nzcv, FPSCR | 
 |  | 
 |   // Branch instructions. | 
 |   void b(Label* label, Condition cond = AL); | 
 |   void bl(Label* label, Condition cond = AL); | 
 |   void blx(Register rm, Condition cond = AL); | 
 |   void bx(Register rm, Condition cond = AL); | 
 |  | 
 |   // Macros. | 
 |   // Add signed constant value to rd. May clobber IP. | 
 |   void AddConstant(Register rd, int32_t value, Condition cond = AL); | 
 |   void AddConstant(Register rd, Register rn, int32_t value, | 
 |                    Condition cond = AL); | 
 |   void AddConstantSetFlags(Register rd, Register rn, int32_t value, | 
 |                            Condition cond = AL); | 
 |   void AddConstantWithCarry(Register rd, Register rn, int32_t value, | 
 |                             Condition cond = AL); | 
 |  | 
 |   // Load and Store. May clobber IP. | 
 |   void LoadImmediate(Register rd, int32_t value, Condition cond = AL); | 
 |   void LoadSImmediate(SRegister sd, float value, Condition cond = AL); | 
 |   void LoadDImmediate(DRegister dd, double value, | 
 |                       Register scratch, Condition cond = AL); | 
 |   void MarkExceptionHandler(Label* label); | 
 |   void LoadFromOffset(LoadOperandType type, | 
 |                       Register reg, | 
 |                       Register base, | 
 |                       int32_t offset, | 
 |                       Condition cond = AL); | 
 |   void StoreToOffset(StoreOperandType type, | 
 |                      Register reg, | 
 |                      Register base, | 
 |                      int32_t offset, | 
 |                      Condition cond = AL); | 
 |   void LoadSFromOffset(SRegister reg, | 
 |                        Register base, | 
 |                        int32_t offset, | 
 |                        Condition cond = AL); | 
 |   void StoreSToOffset(SRegister reg, | 
 |                       Register base, | 
 |                       int32_t offset, | 
 |                       Condition cond = AL); | 
 |   void LoadDFromOffset(DRegister reg, | 
 |                        Register base, | 
 |                        int32_t offset, | 
 |                        Condition cond = AL); | 
 |   void StoreDToOffset(DRegister reg, | 
 |                       Register base, | 
 |                       int32_t offset, | 
 |                       Condition cond = AL); | 
 |  | 
 |   void Push(Register rd, Condition cond = AL); | 
 |   void Pop(Register rd, Condition cond = AL); | 
 |  | 
 |   void PushList(RegList regs, Condition cond = AL); | 
 |   void PopList(RegList regs, Condition cond = AL); | 
 |  | 
 |   void Mov(Register rd, Register rm, Condition cond = AL); | 
 |  | 
 |   // Convenience shift instructions. Use mov instruction with shifter operand | 
 |   // for variants setting the status flags or using a register shift count. | 
 |   void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); | 
 |   void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); | 
 |   void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); | 
 |   void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL); | 
 |   void Rrx(Register rd, Register rm, Condition cond = AL); | 
 |  | 
 |   // Encode a signed constant in tst instructions, only affecting the flags. | 
 |   void EncodeUint32InTstInstructions(uint32_t data); | 
 |   // ... and decode from a pc pointing to the start of encoding instructions. | 
 |   static uint32_t DecodeUint32FromTstInstructions(uword pc); | 
 |   static bool IsInstructionForExceptionHandling(uword pc); | 
 |  | 
 |   // Emit data (e.g. encoded instruction or immediate) to the | 
 |   // instruction stream. | 
 |   void Emit(int32_t value); | 
 |   void Bind(Label* label); | 
 |  | 
 |   // | 
 |   // 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 src, size_t size); | 
 |   virtual void StoreRef(FrameOffset dest, ManagedRegister src); | 
 |   virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src); | 
 |  | 
 |   virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, | 
 |                                      ManagedRegister scratch); | 
 |  | 
 |   virtual void StoreImmediateToThread(ThreadOffset dest, uint32_t imm, | 
 |                                       ManagedRegister scratch); | 
 |  | 
 |   virtual void StoreStackOffsetToThread(ThreadOffset thr_offs, | 
 |                                         FrameOffset fr_offs, | 
 |                                         ManagedRegister scratch); | 
 |  | 
 |   virtual void StoreStackPointerToThread(ThreadOffset thr_offs); | 
 |  | 
 |   virtual void StoreSpanning(FrameOffset dest, ManagedRegister src, | 
 |                              FrameOffset in_off, ManagedRegister scratch); | 
 |  | 
 |   // Load routines | 
 |   virtual void Load(ManagedRegister dest, FrameOffset src, size_t size); | 
 |  | 
 |   virtual void Load(ManagedRegister dest, ThreadOffset src, size_t size); | 
 |  | 
 |   virtual void LoadRef(ManagedRegister dest, FrameOffset  src); | 
 |  | 
 |   virtual void LoadRef(ManagedRegister dest, ManagedRegister base, | 
 |                        MemberOffset offs); | 
 |  | 
 |   virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, | 
 |                           Offset offs); | 
 |  | 
 |   virtual void LoadRawPtrFromThread(ManagedRegister dest, | 
 |                                     ThreadOffset offs); | 
 |  | 
 |   // Copying routines | 
 |   virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size); | 
 |  | 
 |   virtual void CopyRawPtrFromThread(FrameOffset fr_offs, ThreadOffset thr_offs, | 
 |                                     ManagedRegister scratch); | 
 |  | 
 |   virtual void CopyRawPtrToThread(ThreadOffset thr_offs, FrameOffset fr_offs, | 
 |                                   ManagedRegister scratch); | 
 |  | 
 |   virtual void CopyRef(FrameOffset dest, FrameOffset src, | 
 |                        ManagedRegister scratch); | 
 |  | 
 |   virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size); | 
 |  | 
 |   virtual void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, | 
 |                     ManagedRegister scratch, size_t size); | 
 |  | 
 |   virtual void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, | 
 |                     ManagedRegister scratch, size_t size); | 
 |  | 
 |   virtual void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, | 
 |                     ManagedRegister scratch, size_t size); | 
 |  | 
 |   virtual void Copy(ManagedRegister dest, Offset dest_offset, | 
 |                     ManagedRegister src, Offset src_offset, | 
 |                     ManagedRegister scratch, size_t size); | 
 |  | 
 |   virtual void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, | 
 |                     ManagedRegister scratch, size_t size); | 
 |  | 
 |   virtual void MemoryBarrier(ManagedRegister scratch); | 
 |  | 
 |   // 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 scratch); | 
 |  | 
 |   // 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 scratch, 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 scratch); | 
 |   virtual void Call(FrameOffset base, Offset offset, | 
 |                     ManagedRegister scratch); | 
 |   virtual void Call(ThreadOffset offset, ManagedRegister scratch); | 
 |  | 
 |   // Generate code to check if Thread::Current()->exception_ is non-null | 
 |   // and branch to a ExceptionSlowPath if it is. | 
 |   virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust); | 
 |  | 
 |  private: | 
 |   void EmitType01(Condition cond, | 
 |                   int type, | 
 |                   Opcode opcode, | 
 |                   int set_cc, | 
 |                   Register rn, | 
 |                   Register rd, | 
 |                   ShifterOperand so); | 
 |  | 
 |   void EmitType5(Condition cond, int offset, bool link); | 
 |  | 
 |   void EmitMemOp(Condition cond, | 
 |                  bool load, | 
 |                  bool byte, | 
 |                  Register rd, | 
 |                  Address ad); | 
 |  | 
 |   void EmitMemOpAddressMode3(Condition cond, | 
 |                              int32_t mode, | 
 |                              Register rd, | 
 |                              Address ad); | 
 |  | 
 |   void EmitMultiMemOp(Condition cond, | 
 |                       BlockAddressMode am, | 
 |                       bool load, | 
 |                       Register base, | 
 |                       RegList regs); | 
 |  | 
 |   void EmitShiftImmediate(Condition cond, | 
 |                           Shift opcode, | 
 |                           Register rd, | 
 |                           Register rm, | 
 |                           ShifterOperand so); | 
 |  | 
 |   void EmitShiftRegister(Condition cond, | 
 |                          Shift opcode, | 
 |                          Register rd, | 
 |                          Register rm, | 
 |                          ShifterOperand so); | 
 |  | 
 |   void EmitMulOp(Condition cond, | 
 |                  int32_t opcode, | 
 |                  Register rd, | 
 |                  Register rn, | 
 |                  Register rm, | 
 |                  Register rs); | 
 |  | 
 |   void EmitVFPsss(Condition cond, | 
 |                   int32_t opcode, | 
 |                   SRegister sd, | 
 |                   SRegister sn, | 
 |                   SRegister sm); | 
 |  | 
 |   void EmitVFPddd(Condition cond, | 
 |                   int32_t opcode, | 
 |                   DRegister dd, | 
 |                   DRegister dn, | 
 |                   DRegister dm); | 
 |  | 
 |   void EmitVFPsd(Condition cond, | 
 |                  int32_t opcode, | 
 |                  SRegister sd, | 
 |                  DRegister dm); | 
 |  | 
 |   void EmitVFPds(Condition cond, | 
 |                  int32_t opcode, | 
 |                  DRegister dd, | 
 |                  SRegister sm); | 
 |  | 
 |   void EmitBranch(Condition cond, Label* label, bool link); | 
 |   static int32_t EncodeBranchOffset(int offset, int32_t inst); | 
 |   static int DecodeBranchOffset(int32_t inst); | 
 |   int32_t EncodeTstOffset(int offset, int32_t inst); | 
 |   int DecodeTstOffset(int32_t inst); | 
 |  | 
 |   // Returns whether or not the given register is used for passing parameters. | 
 |   static int RegisterCompare(const Register* reg1, const Register* reg2) { | 
 |     return *reg1 - *reg2; | 
 |   } | 
 | }; | 
 |  | 
 | // Slowpath entered when Thread::Current()->_exception is non-null | 
 | class ArmExceptionSlowPath : public SlowPath { | 
 |  public: | 
 |   explicit ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust) | 
 |       : scratch_(scratch), stack_adjust_(stack_adjust) { | 
 |   } | 
 |   virtual void Emit(Assembler *sp_asm); | 
 |  private: | 
 |   const ArmManagedRegister scratch_; | 
 |   const size_t stack_adjust_; | 
 | }; | 
 |  | 
 | }  // namespace arm | 
 | }  // namespace art | 
 |  | 
 | #endif  // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ |