Add the implementation for the ARM assembler.

Change-Id: Iabeb834c3cc2b00a043bd79f9e1c4573d0f0a934
diff --git a/src/assembler_arm.h b/src/assembler_arm.h
index 8ba9906..b625249 100644
--- a/src/assembler_arm.h
+++ b/src/assembler_arm.h
@@ -3,9 +3,502 @@
 #ifndef ART_SRC_ASSEMBLER_ARM_H_
 #define ART_SRC_ASSEMBLER_ARM_H_
 
+#include "src/constants_arm.h"
+#include "src/logging.h"
+#include "src/utils.h"
+
 namespace art {
 
+// 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 Assembler;
+#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(offset < 256);
+    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(IsAligned(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 Assembler;
+};
+
+
 class Assembler {
+ public:
+  Assembler() : buffer_() {}
+
+  // 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);
+
+  // 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);
+
+  // Debugging and bringup support.
+  void Stop(const char* message);
+  void Unimplemented(const char* message);
+  void Untested(const char* message);
+  void Unreachable(const char* message);
+
+  // Emit data (e.g. encoded instruction or immediate) to the
+  // instruction stream.
+  void Emit(int32_t value);
+
+  void Bind(Label* label);
+
+ private:
+  AssemblerBuffer buffer_;
+
+  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;
+  }
 };
 
 } // namespace art