Beginning of X86 encoding map and instruction size routine.

Change-Id: Idaa0d5e0852d7bcfeabff443a45223a078ad02d2
diff --git a/src/compiler/codegen/x86/Assemble.cc b/src/compiler/codegen/x86/Assemble.cc
index f098e66..722f7bb 100644
--- a/src/compiler/codegen/x86/Assemble.cc
+++ b/src/compiler/codegen/x86/Assemble.cc
@@ -24,66 +24,121 @@
 
 #define MAX_ASSEMBLER_RETRIES 50
 
-/*
- * opcode: X86OpCode enum
- * skeleton: pre-designated bit-pattern for this opcode
- * k0: key to applying ds/de
- * ds: dest start bit position
- * de: dest end bit position
- * k1: key to applying s1s/s1e
- * s1s: src1 start bit position
- * s1e: src1 end bit position
- * k2: key to applying s2s/s2e
- * s2s: src2 start bit position
- * s2e: src2 end bit position
- * operands: number of operands (for sanity check purposes)
- * name: mnemonic name
- * fmt: for pretty-printing
- */
-#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
-                     k3, k3s, k3e, flags, name, fmt, size) \
-        {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
-                    {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
+#define BINARY_ENCODING_MAP(opcode, \
+                            rm8_r8, rm32_r32, \
+                            r8_rm8, r32_rm32, \
+                            rax8_i8, rax32_i32, \
+                            rm8_i8_opcode, rm8_i8_modrm, \
+                            rm32_i32_opcode, rm32_i32_modrm, \
+                            rm32_i8_opcode, rm32_i8_modrm) \
+{ kOp ## opcode ## RI, \
+  kRegImm, \
+  0, \
+  { RegMem_Immediate: { rax8_i8, rax32_i32, \
+                       {rm8_i8_opcode, rm8_i8_modrm}, \
+                       {rm32_i32_opcode, rm32_i32_modrm}, \
+                       {rm32_i8_opcode, rm32_i8_modrm} } }, \
+  #opcode "RI", "" \
+}, \
+{ kOp ## opcode ## MI, \
+  kMemImm, \
+  0, \
+  { RegMem_Immediate: { rax8_i8, rax32_i32, \
+                       {rm8_i8_opcode, rm8_i8_modrm}, \
+                       {rm32_i32_opcode, rm32_i32_modrm}, \
+                       {rm32_i8_opcode, rm32_i8_modrm} } }, \
+  #opcode "MI", "" \
+}, \
+{ kOp ## opcode ## AI, \
+  kArrayImm, \
+  0, \
+  { RegMem_Immediate: { rax8_i8, rax32_i32, \
+                       {rm8_i8_opcode, rm8_i8_modrm}, \
+                       {rm32_i32_opcode, rm32_i32_modrm}, \
+                       {rm32_i8_opcode, rm32_i8_modrm} } }, \
+  #opcode "AI", "" \
+}, \
+{ kOp ## opcode ## RR, \
+  kRegReg, \
+  0, \
+  { Reg_RegMem: {r8_rm8, r32_rm32} }, \
+  #opcode "RR", "" \
+}, \
+{ kOp ## opcode ## RM, \
+  kRegMem, \
+  0, \
+  { Reg_RegMem: {r8_rm8, r32_rm32} }, \
+  #opcode "RM", "" \
+}, \
+{ kOp ## opcode ## RA, \
+  kRegArray, \
+  0, \
+  { Reg_RegMem: {r8_rm8, r32_rm32} }, \
+  #opcode "RA", "" \
+}, \
+{ kOp ## opcode ## MR, \
+  kMemReg, \
+  0, \
+  { RegMem_Reg: {rm8_r8, rm32_r32} }, \
+  #opcode "MR", "" \
+}, \
+{ kOp ## opcode ## AR, \
+  kArrayReg, \
+  0, \
+  { RegMem_Reg: {rm8_r8, rm32_r32} }, \
+  #opcode "AR", "" \
+}
 
-/* Instruction dump string format keys: !pf, where "!" is the start
- * of the key, "p" is which numeric operand to use and "f" is the
- * print format.
- *
- * [p]ositions:
- *     0 -> operands[0] (dest)
- *     1 -> operands[1] (src1)
- *     2 -> operands[2] (src2)
- *     3 -> operands[3] (extra)
- *
- * [f]ormats:
- *     h -> 4-digit hex
- *     d -> decimal
- *     E -> decimal*4
- *     F -> decimal*2
- *     c -> branch condition (beq, bne, etc.)
- *     t -> pc-relative target
- *     T -> pc-region target
- *     u -> 1st half of bl[x] target
- *     v -> 2nd half ob bl[x] target
- *     R -> register list
- *     s -> single precision floating point register
- *     S -> double precision floating point register
- *     m -> Thumb2 modified immediate
- *     n -> complimented Thumb2 modified immediate
- *     M -> Thumb2 16-bit zero-extended immediate
- *     b -> 4-digit binary
- *     N -> append a NOP
- *
- *  [!] escape.  To insert "!", use "!!"
- */
-/* NOTE: must be kept in sync with enum X86Opcode from LIR.h */
-/*
- * TUNING: We're currently punting on the branch delay slots.  All branch
- * instructions in this map are given a size of 8, which during assembly
- * is expanded to include a nop.  This scheme should be replaced with
- * an assembler pass to fill those slots when possible.
- */
 X86EncodingMap EncodingMap[kX86Last] = {
+  { kX8632BitData, kData, 0 /* flags - TODO */, { unused: 0 }, "data", "" },
+BINARY_ENCODING_MAP(Add,
+  0x00 /* RegMem8/Reg8 */,     0x01 /* RegMem32/Reg32 */,
+  0x02 /* Reg8/RegMem8 */,     0x03 /* Reg32/RegMem32 */,
+  0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */,
+  0x80, 0x0 /* RegMem8/imm8 */,
+  0x81, 0x0 /* RegMem32/imm32 */, 0x83, 0x0 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(Or,
+  0x08 /* RegMem8/Reg8 */,     0x09 /* RegMem32/Reg32 */,
+  0x0A /* Reg8/RegMem8 */,     0x0B /* Reg32/RegMem32 */,
+  0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */,
+  0x80, 0x1 /* RegMem8/imm8 */,
+  0x81, 0x1 /* RegMem32/imm32 */, 0x83, 0x1 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(Adc,
+  0x10 /* RegMem8/Reg8 */,     0x11 /* RegMem32/Reg32 */,
+  0x12 /* Reg8/RegMem8 */,     0x13 /* Reg32/RegMem32 */,
+  0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */,
+  0x80, 0x2 /* RegMem8/imm8 */,
+  0x81, 0x2 /* RegMem32/imm32 */, 0x83, 0x2 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(Sbb,
+  0x18 /* RegMem8/Reg8 */,     0x19 /* RegMem32/Reg32 */,
+  0x1A /* Reg8/RegMem8 */,     0x1B /* Reg32/RegMem32 */,
+  0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */,
+  0x80, 0x3 /* RegMem8/imm8 */,
+  0x81, 0x3 /* RegMem32/imm32 */, 0x83, 0x3 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(And,
+  0x20 /* RegMem8/Reg8 */,     0x21 /* RegMem32/Reg32 */,
+  0x22 /* Reg8/RegMem8 */,     0x23 /* Reg32/RegMem32 */,
+  0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */,
+  0x80, 0x4 /* RegMem8/imm8 */,
+  0x81, 0x4 /* RegMem32/imm32 */, 0x83, 0x4 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(Sub,
+  0x28 /* RegMem8/Reg8 */,     0x29 /* RegMem32/Reg32 */,
+  0x2A /* Reg8/RegMem8 */,     0x2B /* Reg32/RegMem32 */,
+  0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */,
+  0x80, 0x5 /* RegMem8/imm8 */,
+  0x81, 0x5 /* RegMem32/imm32 */, 0x83, 0x5 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(Xor,
+  0x30 /* RegMem8/Reg8 */,     0x31 /* RegMem32/Reg32 */,
+  0x32 /* Reg8/RegMem8 */,     0x33 /* Reg32/RegMem32 */,
+  0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */,
+  0x80, 0x6 /* RegMem8/imm8 */,
+  0x81, 0x6 /* RegMem32/imm32 */, 0x83, 0x6 /* RegMem32/imm8 */),
+BINARY_ENCODING_MAP(Cmp,
+  0x38 /* RegMem8/Reg8 */,     0x39 /* RegMem32/Reg32 */,
+  0x3A /* Reg8/RegMem8 */,     0x3B /* Reg32/RegMem32 */,
+  0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */,
+  0x80, 0x7 /* RegMem8/imm8 */,
+  0x81, 0x7 /* RegMem32/imm32 */, 0x83, 0x7 /* RegMem32/imm8 */)
 };
 
 
@@ -288,7 +343,55 @@
 
 int oatGetInsnSize(LIR* lir)
 {
-    return EncodingMap[lir->opcode].size;
+  switch (EncodingMap[lir->opcode].kind) {
+    case kData:
+      return 4;
+    case kRegImm: {
+      int reg = lir->operands[0];
+      int imm = lir->operands[1];
+      return (reg == rAX ? 1 : 2) +  // AX opcodes don't require the modrm byte
+             (IS_SIMM8(imm) ? 1 : 4);  // 1 or 4 byte immediate
+      break;
+    }
+    case kMemImm: {
+      // int base = lir->operands[0];
+      int disp = lir->operands[1];
+      int imm  = lir->operands[2];
+      return 2 +  // opcode and modrm bytes
+          (disp == 0 ? 0 : (IS_SIMM8(disp) ? 1 : 4)) +  // 0, 1 or 4 byte displacement
+          (IS_SIMM8(imm) ? 1 : 4);  // 1 or 4 byte immediate
+      break;
+    }
+    case kArrayImm:
+      UNIMPLEMENTED(FATAL);
+      return 0;
+    case kRegReg:
+      return 2;  // opcode and modrm
+    case kRegMem: {
+      // int reg =  lir->operands[0];
+      // int base = lir->operands[1];
+      int disp = lir->operands[2];
+      return 2 +  // opcode and modrm bytes
+          (disp == 0 ? 0 : (IS_SIMM8(disp) ? 1 : 4));  // 0, 1 or 4 byte displacement
+      break;
+    }
+    case kRegArray:
+      UNIMPLEMENTED(FATAL);
+      return 0;
+    case kMemReg: {
+      // int base =  lir->operands[0];
+      int disp = lir->operands[1];
+      // int reg = lir->operands[2];
+      return 2 +  // opcode and modrm bytes
+          (disp == 0 ? 0 : (IS_SIMM8(disp) ? 1 : 4));  // 0, 1 or 4 byte displacement
+      break;
+    }
+    case kArrayReg:
+      UNIMPLEMENTED(FATAL);
+      return 0;
+  }
+  UNIMPLEMENTED(FATAL);  // unreachable
+  return 0;
 }
 /*
  * Target-dependent offset assignment.
diff --git a/src/compiler/codegen/x86/Codegen.h b/src/compiler/codegen/x86/Codegen.h
index 520d638..2fb2df2 100644
--- a/src/compiler/codegen/x86/Codegen.h
+++ b/src/compiler/codegen/x86/Codegen.h
@@ -40,7 +40,7 @@
 LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
                     int checkValue, LIR* target);
 
-/* Forward declaraton the portable versions due to circular dependency */
+/* Forward declaration of the portable versions due to circular dependency */
 bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
                                     RegLocation rlDest, RegLocation rlSrc1,
                                     RegLocation rlSrc2);
diff --git a/src/compiler/codegen/x86/X86LIR.h b/src/compiler/codegen/x86/X86LIR.h
index 31f86af..13488fe 100644
--- a/src/compiler/codegen/x86/X86LIR.h
+++ b/src/compiler/codegen/x86/X86LIR.h
@@ -251,15 +251,21 @@
     kPseudoPseudoAlign4 = -3,
     kPseudoEHBlockLabel = -2,
     kPseudoNormalBlockLabel = -1,
-    kOpAddRR,  // add reg, reg
-    kOpAddRM,  // add reg, [reg + displacement]
-    kOpAddMR,  // add [reg + displacement], reg
-    kOpAddRI,  // add reg, #immediate
-    kOpAddMI,  // add [reg + displacement], #immediate
-    kOpAddRA,  // add reg, [base reg + index reg * scale + displacment]
-    kOpAddAR,  // add [base reg + index reg * scale + displacment], reg
-    kOpAddAI,  // add [base reg + index reg * scale + displacment], #immediate
     kX86First,
+    kX8632BitData = kX86First, /* data [31..0] */
+#define BinaryOpCode(opcode) \
+  opcode ## RI, opcode ## MI, opcode ##AI, \
+  opcode ## RR, opcode ## RM, opcode ##RA, \
+  opcode ## MR, opcode ## AR
+    BinaryOpCode(kOpAdd),
+    BinaryOpCode(kOpOr),
+    BinaryOpCode(kOpAdc),
+    BinaryOpCode(kOpSbb),
+    BinaryOpCode(kOpAnd),
+    BinaryOpCode(kOpSub),
+    BinaryOpCode(kOpXor),
+    BinaryOpCode(kOpCmp),
+#undef BinaryOpCode
     kX86Last
 } X86OpCode;
 
@@ -344,19 +350,42 @@
 
 /* Instruction assembly fieldLoc kind */
 typedef enum X86EncodingKind {
-    kFmtUnused,
-    kFmtBitBlt,        /* Bit string using end/start */
-    kFmtDfp,           /* Double FP reg */
-    kFmtSfp,           /* Single FP reg */
+  kData,
+  kRegImm, kMemImm, kArrayImm,
+  kRegReg, kRegMem, kRegArray,
+  kMemReg, kArrayReg
 } X86EncodingKind;
 
 /* Struct used to define the snippet positions for each X86 opcode */
+typedef struct OpcodeModRMOpcode {
+  uint8_t opcode;
+  uint8_t modrm_opcode;
+} OpcodeModRMOpcode;
+
 typedef struct X86EncodingMap {
-    X86OpCode opcode;
-    int flags;
-    const char *name;
-    const char* fmt;
-    int size;     /* Size in bytes */
+  X86OpCode opcode;      // e.g. kOpAddRI
+  X86EncodingKind kind;  // Used to discriminate in the union below
+  int flags;
+  union {
+    struct {
+      uint8_t rax8_i8_opcode;
+      uint8_t rax32_i32_opcode;
+      OpcodeModRMOpcode rm8_i8_opcode;
+      OpcodeModRMOpcode rm32_i32_opcode;
+      OpcodeModRMOpcode rm32_i8_opcode;
+    } RegMem_Immediate;  // kind: kRegImm, kMemImm, kArrayImm
+    struct {
+      uint8_t r8_rm8_opcode;
+      uint8_t r32_rm32_opcode;
+    } Reg_RegMem;  // kind: kRegReg, kRegMem, kRegArray,
+    struct {
+      uint8_t rm8_r8_opcode;
+      uint8_t rm32_r32_opcode;
+    } RegMem_Reg;  // kind: kMemReg, kArrayReg
+    int unused;  // kind: kData
+  } skeleton;
+  const char *name;
+  const char* fmt;
 } X86EncodingMap;
 
 /* Keys for target-specific scheduling and other optimization hints */
@@ -366,9 +395,7 @@
 
 extern X86EncodingMap EncodingMap[kX86Last];
 
-#define IS_UIMM16(v) ((0 <= (v)) && ((v) <= 65535))
-#define IS_SIMM16(v) ((-32768 <= (v)) && ((v) <= 32766))
-#define IS_SIMM16_2WORD(v) ((-32764 <= (v)) && ((v) <= 32763)) /* 2 offsets must fit */
+#define IS_SIMM8(v) ((-128 <= (v)) && ((v) <= 128))
 
 }  // namespace art