blob: b62b5b4d5344e5b7459b6adb673321e70282fb3d [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "../../Dalvik.h"
18#include "../../CompilerInternals.h"
19#include "X86LIR.h"
20#include "Codegen.h"
21#include <sys/mman.h> /* for protection change */
22
23namespace art {
24
25#define MAX_ASSEMBLER_RETRIES 50
26
buzbeea7678db2012-03-05 15:35:46 -080027X86EncodingMap EncodingMap[kX86Last] = {
Ian Rogersb5d09b22012-03-06 22:14:17 -080028 { kX8632BitData, kData, IS_UNARY_OP, { 0, 0, 0x00, 0, 0, 0, 0, 4 }, "data", "0x!0d" },
29 { kX86Bkpt, kNullary, NO_OPERAND | IS_BRANCH, { 0, 0, 0xCC, 0, 0, 0, 0, 4 }, "int 3", "" },
30 { kX86Nop, kNop, IS_UNARY_OP, { 0, 0, 0x90, 0, 0, 0, 0, 0 }, "nop", "" },
31
Ian Rogersb3ab25b2012-03-19 01:12:01 -070032#define ENCODING_MAP(opname, is_store, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080033 rm8_r8, rm32_r32, \
34 r8_rm8, r32_rm32, \
35 ax8_i8, ax32_i32, \
36 rm8_i8, rm8_i8_modrm, \
37 rm32_i32, rm32_i32_modrm, \
38 rm32_i8, rm32_i8_modrm) \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070039{ kX86 ## opname ## 8MR, kMemReg, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, rm8_r8, 0, 0, 0, 0, 0 }, #opname "8MR", "[!0r+!1d],!2r" }, \
40{ kX86 ## opname ## 8AR, kArrayReg, is_store | IS_QUIN_OP | SETS_CCODES, { 0, 0, rm8_r8, 0, 0, 0, 0, 0 }, #opname "8AR", "[!0r+!1r<<!2d+!3d],!4r" }, \
41{ kX86 ## opname ## 8TR, kThreadReg,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, rm8_r8, 0, 0, 0, 0, 0 }, #opname "8TR", "fs:[!0d],!1r" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080042{ kX86 ## opname ## 8RR, kRegReg, IS_BINARY_OP | SETS_CCODES, { 0, 0, r8_rm8, 0, 0, 0, 0, 0 }, #opname "8RR", "!0r,!1r" }, \
43{ kX86 ## opname ## 8RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, r8_rm8, 0, 0, 0, 0, 0 }, #opname "8RM", "!0r,[!1r+!2d]" }, \
44{ kX86 ## opname ## 8RA, kRegArray, IS_LOAD | IS_QUIN_OP | SETS_CCODES, { 0, 0, r8_rm8, 0, 0, 0, 0, 0 }, #opname "8RA", "!0r,[!1r+!2r<<!3d+!4d]" }, \
45{ kX86 ## opname ## 8RT, kRegThread, IS_LOAD | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, r8_rm8, 0, 0, 0, 0, 0 }, #opname "8RT", "!0r,fs:[!1d]" }, \
46{ kX86 ## opname ## 8RI, kRegImm, IS_BINARY_OP | SETS_CCODES, { 0, 0, rm8_i8, 0, 0, rm8_i8_modrm, ax8_i8, 1 }, #opname "8RI", "!0r,!1d" }, \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070047{ kX86 ## opname ## 8MI, kMemImm, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, rm8_i8, 0, 0, rm8_i8_modrm, 0, 1 }, #opname "8MI", "[!0r+!1d],!2r" }, \
48{ kX86 ## opname ## 8AI, kArrayImm, is_store | IS_QUIN_OP | SETS_CCODES, { 0, 0, rm8_i8, 0, 0, rm8_i8_modrm, 0, 1 }, #opname "8AI", "[!0r+!1r<<!2d+!3d],!4r" }, \
49{ kX86 ## opname ## 8TI, kThreadImm,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, rm8_i8, 0, 0, rm8_i8_modrm, 0, 1 }, #opname "8TI", "fs:[!0d],!1r" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080050 \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070051{ kX86 ## opname ## 16MR, kMemReg, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, rm32_r32, 0, 0, 0, 0, 0 }, #opname "16MR", "[!0r+!1d],!2r" }, \
52{ kX86 ## opname ## 16AR, kArrayReg, is_store | IS_QUIN_OP | SETS_CCODES, { 0x66, 0, rm32_r32, 0, 0, 0, 0, 0 }, #opname "16AR", "[!0r+!1r<<!2d+!3d],!4r" }, \
53{ kX86 ## opname ## 16TR, kThreadReg,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0x66, rm32_r32, 0, 0, 0, 0, 0 }, #opname "16TR", "fs:[!0d],!1r" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080054{ kX86 ## opname ## 16RR, kRegReg, IS_BINARY_OP | SETS_CCODES, { 0x66, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "16RR", "!0r,!1r" }, \
55{ kX86 ## opname ## 16RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "16RM", "!0r,[!1r+!2d]" }, \
56{ kX86 ## opname ## 16RA, kRegArray, IS_LOAD | IS_QUIN_OP | SETS_CCODES, { 0x66, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "16RA", "!0r,[!1r+!2r<<!3d+!4d]" }, \
57{ kX86 ## opname ## 16RT, kRegThread, IS_LOAD | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0x66, r32_rm32, 0, 0, 0, 0, 0 }, #opname "16RT", "!0r,fs:[!1d]" }, \
58{ kX86 ## opname ## 16RI, kRegImm, IS_BINARY_OP | SETS_CCODES, { 0x66, 0, rm32_i32, 0, 0, rm32_i32_modrm, ax32_i32, 2 }, #opname "16RI", "!0r,!1d" }, \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070059{ kX86 ## opname ## 16MI, kMemImm, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, rm32_i32, 0, 0, rm32_i32_modrm, 0, 2 }, #opname "16MI", "[!0r+!1d],!2d" }, \
60{ kX86 ## opname ## 16AI, kArrayImm, is_store | IS_QUIN_OP | SETS_CCODES, { 0x66, 0, rm32_i32, 0, 0, rm32_i32_modrm, 0, 2 }, #opname "16AI", "[!0r+!1r<<!2d+!3d],!4d" }, \
61{ kX86 ## opname ## 16TI, kThreadImm,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0x66, rm32_i32, 0, 0, rm32_i32_modrm, 0, 2 }, #opname "16TI", "fs:[!0d],!1d" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080062{ kX86 ## opname ## 16RI8, kRegImm, IS_BINARY_OP | SETS_CCODES, { 0x66, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "16RI8", "!0r,!1d" }, \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070063{ kX86 ## opname ## 16MI8, kMemImm, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "16MI8", "[!0r+!1d],!2d" }, \
64{ kX86 ## opname ## 16AI8, kArrayImm, is_store | IS_QUIN_OP | SETS_CCODES, { 0x66, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "16AI8", "[!0r+!1r<<!2d+!3d],!4d" }, \
65{ kX86 ## opname ## 16TI8, kThreadImm,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0x66, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "16TI8", "fs:[!0d],!1d" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080066 \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070067{ kX86 ## opname ## 32MR, kMemReg, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, rm32_r32, 0, 0, 0, 0, 0 }, #opname "32MR", "[!0r+!1d],!2r" }, \
68{ kX86 ## opname ## 32AR, kArrayReg, is_store | IS_QUIN_OP | SETS_CCODES, { 0, 0, rm32_r32, 0, 0, 0, 0, 0 }, #opname "32AR", "[!0r+!1r<<!2d+!3d],!4r" }, \
69{ kX86 ## opname ## 32TR, kThreadReg,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, rm32_r32, 0, 0, 0, 0, 0 }, #opname "32TR", "fs:[!0d],!1r" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080070{ kX86 ## opname ## 32RR, kRegReg, IS_BINARY_OP | SETS_CCODES, { 0, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "32RR", "!0r,!1r" }, \
71{ kX86 ## opname ## 32RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "32RM", "!0r,[!1r+!2d]" }, \
72{ kX86 ## opname ## 32RA, kRegArray, IS_LOAD | IS_QUIN_OP | SETS_CCODES, { 0, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "32RA", "!0r,[!1r+!2r<<!3d+!4d]" }, \
73{ kX86 ## opname ## 32RT, kRegThread, IS_LOAD | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, r32_rm32, 0, 0, 0, 0, 0 }, #opname "32RT", "!0r,fs:[!1d]" }, \
74{ kX86 ## opname ## 32RI, kRegImm, IS_BINARY_OP | SETS_CCODES, { 0, 0, rm32_i32, 0, 0, rm32_i32_modrm, ax32_i32, 4 }, #opname "32RI", "!0r,!1d" }, \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070075{ kX86 ## opname ## 32MI, kMemImm, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, rm32_i32, 0, 0, rm32_i32_modrm, 0, 4 }, #opname "32MI", "[!0r+!1d],!2r" }, \
76{ kX86 ## opname ## 32AI, kArrayImm, is_store | IS_QUIN_OP | SETS_CCODES, { 0, 0, rm32_i32, 0, 0, rm32_i32_modrm, 0, 4 }, #opname "32AI", "[!0r+!1r<<!2d+!3d],!4d" }, \
77{ kX86 ## opname ## 32TI, kThreadImm,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, rm32_i32, 0, 0, rm32_i32_modrm, 0, 4 }, #opname "32TI", "fs:[!0d],!1d" }, \
Ian Rogersb5d09b22012-03-06 22:14:17 -080078{ kX86 ## opname ## 32RI8, kRegImm, IS_BINARY_OP | SETS_CCODES, { 0, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "32RI8", "!0r,!1d" }, \
Ian Rogersb3ab25b2012-03-19 01:12:01 -070079{ kX86 ## opname ## 32MI8, kMemImm, is_store | IS_TERTIARY_OP | SETS_CCODES, { 0, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "32MI8", "[!0r+!1d],!2d" }, \
80{ kX86 ## opname ## 32AI8, kArrayImm, is_store | IS_QUIN_OP | SETS_CCODES, { 0, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "32AI8", "[!0r+!1r<<!2d+!3d],!4d" }, \
81{ kX86 ## opname ## 32TI8, kThreadImm,is_store | IS_BINARY_OP | SETS_CCODES, { THREAD_PREFIX, 0, rm32_i8, 0, 0, rm32_i8_modrm, 0, 1 }, #opname "32TI8", "fs:[!0d],!1d" }
Ian Rogersb5d09b22012-03-06 22:14:17 -080082
Ian Rogersb3ab25b2012-03-19 01:12:01 -070083ENCODING_MAP(Add, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -080084 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */,
85 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */,
86 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */,
87 0x80, 0x0 /* RegMem8/imm8 */,
88 0x81, 0x0 /* RegMem32/imm32 */, 0x83, 0x0 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -070089ENCODING_MAP(Or, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -080090 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */,
91 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */,
92 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */,
93 0x80, 0x1 /* RegMem8/imm8 */,
94 0x81, 0x1 /* RegMem32/imm32 */, 0x83, 0x1 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -070095ENCODING_MAP(Adc, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -080096 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */,
97 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */,
98 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */,
99 0x80, 0x2 /* RegMem8/imm8 */,
100 0x81, 0x2 /* RegMem32/imm32 */, 0x83, 0x2 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700101ENCODING_MAP(Sbb, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -0800102 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */,
103 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */,
104 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */,
105 0x80, 0x3 /* RegMem8/imm8 */,
106 0x81, 0x3 /* RegMem32/imm32 */, 0x83, 0x3 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700107ENCODING_MAP(And, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -0800108 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */,
109 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */,
110 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */,
111 0x80, 0x4 /* RegMem8/imm8 */,
112 0x81, 0x4 /* RegMem32/imm32 */, 0x83, 0x4 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700113ENCODING_MAP(Sub, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -0800114 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */,
115 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */,
116 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */,
117 0x80, 0x5 /* RegMem8/imm8 */,
118 0x81, 0x5 /* RegMem32/imm32 */, 0x83, 0x5 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700119ENCODING_MAP(Xor, IS_STORE,
Ian Rogers96ab4202012-03-05 19:51:02 -0800120 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */,
121 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */,
122 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */,
123 0x80, 0x6 /* RegMem8/imm8 */,
124 0x81, 0x6 /* RegMem32/imm32 */, 0x83, 0x6 /* RegMem32/imm8 */),
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700125ENCODING_MAP(Cmp, IS_LOAD,
Ian Rogers96ab4202012-03-05 19:51:02 -0800126 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */,
127 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */,
128 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */,
129 0x80, 0x7 /* RegMem8/imm8 */,
Ian Rogersde797832012-03-06 10:18:10 -0800130 0x81, 0x7 /* RegMem32/imm32 */, 0x83, 0x7 /* RegMem32/imm8 */),
Ian Rogersb5d09b22012-03-06 22:14:17 -0800131#undef ENCODING_MAP
132
133 { kX86Imul16RRI, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RRI", "" },
134 { kX86Imul16RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RMI", "" },
135 { kX86Imul16RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RAI", "" },
136
137 { kX86Imul32RRI, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RRI", "" },
138 { kX86Imul32RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RMI", "" },
139 { kX86Imul32RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RAI", "" },
140 { kX86Imul32RRI8, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RRI8", "" },
141 { kX86Imul32RMI8, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RMI8", "" },
142 { kX86Imul32RAI8, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RAI8", "" },
143
144 { kX86Mov8MR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0, 0, 0x88, 0, 0, 0, 0, 0 }, "Mov8MR", "[!0r+!1d],!2r" },
145 { kX86Mov8AR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0, 0, 0x88, 0, 0, 0, 0, 0 }, "Mov8AR", "[!0r+!1r<<!2d+!3d],!4r" },
146 { kX86Mov8TR, kThreadReg, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0, 0x88, 0, 0, 0, 0, 0 }, "Mov8TR", "fs:[!0d],!1r" },
147 { kX86Mov8RR, kRegReg, IS_BINARY_OP, { 0, 0, 0x8A, 0, 0, 0, 0, 0 }, "Mov8RR", "!0r,!1r" },
148 { kX86Mov8RM, kRegMem, IS_LOAD | IS_TERTIARY_OP, { 0, 0, 0x8A, 0, 0, 0, 0, 0 }, "Mov8RM", "!0r,[!1r+!2d]" },
149 { kX86Mov8RA, kRegArray, IS_LOAD | IS_QUIN_OP, { 0, 0, 0x8A, 0, 0, 0, 0, 0 }, "Mov8RA", "!0r,[!1r+!2r<<!3d+!4d]" },
150 { kX86Mov8RT, kRegThread, IS_LOAD | IS_BINARY_OP, { THREAD_PREFIX, 0, 0x8A, 0, 0, 0, 0, 0 }, "Mov8RT", "!0r,fs:[!1d]" },
151 { kX86Mov8RI, kMovRegImm, IS_BINARY_OP, { 0, 0, 0xB0, 0, 0, 0, 0, 1 }, "Mov8RI", "!0r,!1d" },
152 { kX86Mov8MI, kMemImm, IS_STORE | IS_TERTIARY_OP, { 0, 0, 0xC6, 0, 0, 0, 0, 1 }, "Mov8MI", "[!0r+!1d],!2r" },
153 { kX86Mov8AI, kArrayImm, IS_STORE | IS_QUIN_OP, { 0, 0, 0xC6, 0, 0, 0, 0, 1 }, "Mov8AI", "[!0r+!1r<<!2d+!3d],!4d" },
154 { kX86Mov8TI, kThreadImm, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0, 0xC6, 0, 0, 0, 0, 1 }, "Mov8TI", "fs:[!0d],!1d" },
155
156 { kX86Mov16MR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0x66, 0, 0x89, 0, 0, 0, 0, 0 }, "Mov16MR", "[!0r+!1d],!2r" },
157 { kX86Mov16AR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0x66, 0, 0x89, 0, 0, 0, 0, 0 }, "Mov16AR", "[!0r+!1r<<!2d+!3d],!4r" },
158 { kX86Mov16TR, kThreadReg, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0x66, 0x89, 0, 0, 0, 0, 0 }, "Mov16TR", "fs:[!0d],!1r" },
159 { kX86Mov16RR, kRegReg, IS_BINARY_OP, { 0x66, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov16RR", "!0r,!1r" },
160 { kX86Mov16RM, kRegMem, IS_LOAD | IS_TERTIARY_OP, { 0x66, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov16RM", "!0r,[!1r+!2d]" },
161 { kX86Mov16RA, kRegArray, IS_LOAD | IS_QUIN_OP, { 0x66, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov16RA", "!0r,[!1r+!2r<<!3d+!4d]" },
162 { kX86Mov16RT, kRegThread, IS_LOAD | IS_BINARY_OP, { THREAD_PREFIX, 0x66, 0x8B, 0, 0, 0, 0, 0 }, "Mov16RT", "!0r,fs:[!1d]" },
163 { kX86Mov16RI, kMovRegImm, IS_BINARY_OP, { 0x66, 0, 0xB8, 0, 0, 0, 0, 2 }, "Mov16RI", "!0r,!1d" },
164 { kX86Mov16MI, kMemImm, IS_STORE | IS_TERTIARY_OP, { 0x66, 0, 0xC7, 0, 0, 0, 0, 2 }, "Mov16MI", "[!0r+!1d],!2r" },
165 { kX86Mov16AI, kArrayImm, IS_STORE | IS_QUIN_OP, { 0x66, 0, 0xC7, 0, 0, 0, 0, 2 }, "Mov16AI", "[!0r+!1r<<!2d+!3d],!4d" },
166 { kX86Mov16TI, kThreadImm, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0x66, 0xC7, 0, 0, 0, 0, 2 }, "Mov16TI", "fs:[!0d],!1d" },
167
168 { kX86Mov32MR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0, 0, 0x89, 0, 0, 0, 0, 0 }, "Mov32MR", "[!0r+!1d],!2r" },
169 { kX86Mov32AR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0, 0, 0x89, 0, 0, 0, 0, 0 }, "Mov32AR", "[!0r+!1r<<!2d+!3d],!4r" },
170 { kX86Mov32TR, kThreadReg, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0, 0x89, 0, 0, 0, 0, 0 }, "Mov32TR", "fs:[!0d],!1r" },
171 { kX86Mov32RR, kRegReg, IS_BINARY_OP, { 0, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov32RR", "!0r,!1r" },
172 { kX86Mov32RM, kRegMem, IS_LOAD | IS_TERTIARY_OP, { 0, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov32RM", "!0r,[!1r+!2d]" },
173 { kX86Mov32RA, kRegArray, IS_LOAD | IS_QUIN_OP, { 0, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov32RA", "!0r,[!1r+!2r<<!3d+!4d]" },
174 { kX86Mov32RT, kRegThread, IS_LOAD | IS_BINARY_OP, { THREAD_PREFIX, 0, 0x8B, 0, 0, 0, 0, 0 }, "Mov32RT", "!0r,fs:[!1d]" },
175 { kX86Mov32RI, kMovRegImm, IS_BINARY_OP, { 0, 0, 0xB8, 0, 0, 0, 0, 4 }, "Mov32RI", "!0r,!1d" },
176 { kX86Mov32MI, kMemImm, IS_STORE | IS_TERTIARY_OP, { 0, 0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32MI", "[!0r+!1d],!2r" },
177 { kX86Mov32AI, kArrayImm, IS_STORE | IS_QUIN_OP, { 0, 0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32AI", "[!0r+!1r<<!2d+!3d],!4d" },
178 { kX86Mov32TI, kThreadImm, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32TI", "fs:[!0d],!1d" },
179
180 { kX86Lea32RA, kRegArray, IS_QUIN_OP, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RA", "!0r,[!1r+!2r<<!3d+!4d]" },
181
182#define SHIFT_ENCODING_MAP(opname, modrm_opcode) \
183{ kX86 ## opname ## 8RI, kShiftRegImm, IS_BINARY_OP | SETS_CCODES, { 0, 0, 0xC0, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "8RI", "!0r,!1d" }, \
184{ kX86 ## opname ## 8MI, kShiftMemImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0xC0, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "8MI", "[!0r+!1d],!2r" }, \
185{ kX86 ## opname ## 8AI, kShiftArrayImm, IS_QUIN_OP | SETS_CCODES, { 0, 0, 0xC0, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "8AI", "[!0r+!1r<<!2d+!3d],!4d" }, \
186{ kX86 ## opname ## 8RC, kShiftRegCl, IS_BINARY_OP | SETS_CCODES, { 0, 0, 0xD2, 0, 0, modrm_opcode, 0, 1 }, #opname "8RC", "" }, \
187{ kX86 ## opname ## 8MC, kShiftMemCl, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0xD2, 0, 0, modrm_opcode, 0, 1 }, #opname "8MC", "" }, \
188{ kX86 ## opname ## 8AC, kShiftArrayCl, IS_QUIN_OP | SETS_CCODES, { 0, 0, 0xD2, 0, 0, modrm_opcode, 0, 1 }, #opname "8AC", "" }, \
189 \
190{ kX86 ## opname ## 16RI, kShiftRegImm, IS_BINARY_OP | SETS_CCODES, { 0x66, 0, 0xC1, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "16RI", "!0r,!1d" }, \
191{ kX86 ## opname ## 16MI, kShiftMemImm, IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, 0xC1, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "16MI", "[!0r+!1d],!2r" }, \
192{ kX86 ## opname ## 16AI, kShiftArrayImm, IS_QUIN_OP | SETS_CCODES, { 0x66, 0, 0xC1, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "16AI", "[!0r+!1r<<!2d+!3d],!4d" }, \
193{ kX86 ## opname ## 16RC, kShiftRegCl, IS_BINARY_OP | SETS_CCODES, { 0x66, 0, 0xD3, 0, 0, modrm_opcode, 0, 1 }, #opname "16RC", "" }, \
194{ kX86 ## opname ## 16MC, kShiftMemCl, IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, 0xD3, 0, 0, modrm_opcode, 0, 1 }, #opname "16MC", "" }, \
195{ kX86 ## opname ## 16AC, kShiftArrayCl, IS_QUIN_OP | SETS_CCODES, { 0x66, 0, 0xD3, 0, 0, modrm_opcode, 0, 1 }, #opname "16AC", "" }, \
196 \
197{ kX86 ## opname ## 32RI, kShiftRegImm, IS_BINARY_OP | SETS_CCODES, { 0, 0, 0xC1, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "32RI", "!0r,!1d" }, \
198{ kX86 ## opname ## 32MI, kShiftMemImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0xC1, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "32MI", "[!0r+!1d],!2r" }, \
199{ kX86 ## opname ## 32AI, kShiftArrayImm, IS_QUIN_OP | SETS_CCODES, { 0, 0, 0xC1, 0, 0, modrm_opcode, 0xD1, 1 }, #opname "32AI", "[!0r+!1r<<!2d+!3d],!4d" }, \
200{ kX86 ## opname ## 32RC, kShiftRegCl, IS_BINARY_OP | SETS_CCODES, { 0, 0, 0xD3, 0, 0, modrm_opcode, 0, 1 }, #opname "32RC", "" }, \
201{ kX86 ## opname ## 32MC, kShiftMemCl, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0xD3, 0, 0, modrm_opcode, 0, 1 }, #opname "32MC", "" }, \
202{ kX86 ## opname ## 32AC, kShiftArrayCl, IS_QUIN_OP | SETS_CCODES, { 0, 0, 0xD3, 0, 0, modrm_opcode, 0, 1 }, #opname "32AC", "" }
203
204 SHIFT_ENCODING_MAP(Rol, 0x0),
205 SHIFT_ENCODING_MAP(Ror, 0x1),
206 SHIFT_ENCODING_MAP(Rcl, 0x2),
207 SHIFT_ENCODING_MAP(Rcr, 0x3),
208 SHIFT_ENCODING_MAP(Sal, 0x4),
209 SHIFT_ENCODING_MAP(Shl, 0x5),
210 SHIFT_ENCODING_MAP(Shr, 0x6),
211 SHIFT_ENCODING_MAP(Sar, 0x7),
212#undef SHIFT_ENCODING_MAP
213
214#define UNARY_ENCODING_MAP(opname, modrm, \
215 reg, reg_kind, reg_flags, \
216 mem, mem_kind, mem_flags, \
217 arr, arr_kind, arr_flags, imm) \
218{ kX86 ## opname ## 8 ## reg, reg_kind, reg_flags, { 0, 0, 0xF6, 0, 0, modrm, 0, imm << 0}, #opname "8" #reg, "" }, \
219{ kX86 ## opname ## 8 ## mem, mem_kind, IS_LOAD | mem_flags, { 0, 0, 0xF6, 0, 0, modrm, 0, imm << 0}, #opname "8" #mem, "" }, \
220{ kX86 ## opname ## 8 ## arr, arr_kind, IS_LOAD | arr_flags, { 0, 0, 0xF6, 0, 0, modrm, 0, imm << 0}, #opname "8" #arr, "" }, \
221{ kX86 ## opname ## 16 ## reg, reg_kind, reg_flags, { 0x66, 0, 0xF7, 0, 0, modrm, 0, imm << 1}, #opname "16" #reg, "" }, \
222{ kX86 ## opname ## 16 ## mem, mem_kind, IS_LOAD | mem_flags, { 0x66, 0, 0xF7, 0, 0, modrm, 0, imm << 1}, #opname "16" #mem, "" }, \
223{ kX86 ## opname ## 16 ## arr, arr_kind, IS_LOAD | arr_flags, { 0x66, 0, 0xF7, 0, 0, modrm, 0, imm << 1}, #opname "16" #arr, "" }, \
224{ kX86 ## opname ## 32 ## reg, reg_kind, reg_flags, { 0, 0, 0xF7, 0, 0, modrm, 0, imm << 2}, #opname "32" #reg, "" }, \
225{ kX86 ## opname ## 32 ## mem, mem_kind, IS_LOAD | mem_flags, { 0, 0, 0xF7, 0, 0, modrm, 0, imm << 2}, #opname "32" #mem, "" }, \
226{ kX86 ## opname ## 32 ## arr, arr_kind, IS_LOAD | arr_flags, { 0, 0, 0xF7, 0, 0, modrm, 0, imm << 2}, #opname "32" #arr, "" }
227
228 UNARY_ENCODING_MAP(Test, 0x0, RI, kRegImm, IS_BINARY_OP, MI, kMemImm, IS_TERTIARY_OP, AI, kArrayImm, IS_QUIN_OP, 1),
229 UNARY_ENCODING_MAP(Not, 0x2, R, kReg, IS_UNARY_OP, M, kMem, IS_BINARY_OP, A, kArray, IS_QUAD_OP, 0),
230 UNARY_ENCODING_MAP(Neg, 0x3, R, kReg, IS_UNARY_OP, M, kMem, IS_BINARY_OP, A, kArray, IS_QUAD_OP, 0),
231 UNARY_ENCODING_MAP(Mul, 0x4, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
232 UNARY_ENCODING_MAP(Imul, 0x5, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
233 UNARY_ENCODING_MAP(Divmod, 0x6, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
234 UNARY_ENCODING_MAP(Idivmod, 0x7, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
235#undef UNARY_ENCODING_MAP
236
237#define EXT_0F_ENCODING_MAP(opname, prefix, opcode) \
238{ kX86 ## opname ## RR, kRegReg, IS_BINARY_OP, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \
239{ kX86 ## opname ## RM, kRegMem, IS_LOAD | IS_TERTIARY_OP, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RM", "!0r,[!1r+!2d]" }, \
240{ kX86 ## opname ## RA, kRegArray, IS_LOAD | IS_QUIN_OP, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RA", "!0r,[!1r+!2r<<!3d+!4d]" }
241
242 EXT_0F_ENCODING_MAP(Movsd, 0xF2, 0x10),
243 { kX86MovsdMR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0xF2, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovsdMR", "[!0r+!1d],!2r" },
244 { kX86MovsdAR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0xF2, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovsdAR", "[!0r+!1r<<!2d+!3d],!4r" },
245
246 EXT_0F_ENCODING_MAP(Movss, 0xF3, 0x10),
247 { kX86MovssMR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0xF3, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovssMR", "[!0r+!1d],!2r" },
248 { kX86MovssAR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0xF3, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovssAR", "[!0r+!1r<<!2d+!3d],!4r" },
249
250 EXT_0F_ENCODING_MAP(Cvtsi2sd, 0xF2, 0x2A),
251 EXT_0F_ENCODING_MAP(Cvtsi2ss, 0xF3, 0x2A),
252 EXT_0F_ENCODING_MAP(Cvttsd2si, 0xF2, 0x2C),
253 EXT_0F_ENCODING_MAP(Cvttss2si, 0xF3, 0x2C),
254 EXT_0F_ENCODING_MAP(Cvtsd2si, 0xF2, 0x2D),
255 EXT_0F_ENCODING_MAP(Cvtss2si, 0xF3, 0x2D),
256 EXT_0F_ENCODING_MAP(Ucomisd, 0x66, 0x2E),
257 EXT_0F_ENCODING_MAP(Ucomiss, 0x00, 0x2E),
258 EXT_0F_ENCODING_MAP(Comisd, 0x66, 0x2F),
259 EXT_0F_ENCODING_MAP(Comiss, 0x00, 0x2F),
Ian Rogersb41b33b2012-03-20 14:22:54 -0700260 EXT_0F_ENCODING_MAP(Orps, 0x00, 0x56),
261 EXT_0F_ENCODING_MAP(Xorps, 0x00, 0x57),
Ian Rogersb5d09b22012-03-06 22:14:17 -0800262 EXT_0F_ENCODING_MAP(Addsd, 0xF2, 0x58),
263 EXT_0F_ENCODING_MAP(Addss, 0xF3, 0x58),
264 EXT_0F_ENCODING_MAP(Mulsd, 0xF2, 0x59),
265 EXT_0F_ENCODING_MAP(Mulss, 0xF3, 0x59),
266 EXT_0F_ENCODING_MAP(Cvtss2sd, 0xF2, 0x5A),
267 EXT_0F_ENCODING_MAP(Cvtsd2ss, 0xF3, 0x5A),
268 EXT_0F_ENCODING_MAP(Subsd, 0xF2, 0x5C),
269 EXT_0F_ENCODING_MAP(Subss, 0xF3, 0x5C),
270 EXT_0F_ENCODING_MAP(Divsd, 0xF2, 0x5E),
271 EXT_0F_ENCODING_MAP(Divss, 0xF3, 0x5E),
272
Ian Rogersb41b33b2012-03-20 14:22:54 -0700273 { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 7, 0, 1 }, "PsllqRI", "!0r, !1d" },
274
Ian Rogersb5d09b22012-03-06 22:14:17 -0800275 EXT_0F_ENCODING_MAP(Movdxr, 0x66, 0x6E),
276 EXT_0F_ENCODING_MAP(Movdrx, 0x66, 0x7E),
277
278 { kX86Set8R, kRegCond, IS_BINARY_OP, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8R", "!1c !0r" },
279 { kX86Set8M, kMemCond, IS_STORE | IS_TERTIARY_OP, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8M", "!2c [!0r+!1d]" },
280 { kX86Set8A, kArrayCond, IS_STORE | IS_QUIN_OP, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8A", "!4c [!0r+!1r<<!2d+!3d]" },
281
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700282 // TODO: load/store?
283 // Encode the modrm opcode as an extra opcode byte to avoid computation during assembly.
284 { kX86Mfence, kReg, NO_OPERAND, { 0, 0, 0x0F, 0xAE, 0, 6, 0, 0 }, "Mfence", "" },
285
Ian Rogersb5d09b22012-03-06 22:14:17 -0800286 EXT_0F_ENCODING_MAP(Imul16, 0x66, 0xAF),
287 EXT_0F_ENCODING_MAP(Imul32, 0x00, 0xAF),
288 EXT_0F_ENCODING_MAP(Movzx8, 0x00, 0xB6),
289 EXT_0F_ENCODING_MAP(Movzx16, 0x00, 0xB7),
290 EXT_0F_ENCODING_MAP(Movsx8, 0x00, 0xBE),
291 EXT_0F_ENCODING_MAP(Movsx16, 0x00, 0xBF),
292#undef EXT_0F_ENCODING_MAP
293
Ian Rogersb41b33b2012-03-20 14:22:54 -0700294 { kX86Jcc8, kJcc, IS_BINARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0x70, 0, 0, 0, 0, 0 }, "Jcc8", "!1c !0t" },
295 { kX86Jcc32, kJcc, IS_BINARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0x0F, 0x80, 0, 0, 0, 0 }, "Jcc32", "!1c !0t" },
296 { kX86Jmp8, kJmp, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0xEB, 0, 0, 0, 0, 0 }, "Jmp8", "!0t" },
297 { kX86Jmp32, kJmp, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0xE9, 0, 0, 0, 0, 0 }, "Jmp32", "!0t" },
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700298 { kX86CallR, kCall, IS_UNARY_OP | IS_BRANCH, { 0, 0, 0xE8, 0, 0, 0, 0, 0 }, "CallR", "!0r" },
299 { kX86CallM, kCall, IS_BINARY_OP | IS_BRANCH | IS_LOAD, { 0, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallM", "[!0r+!1d]" },
300 { kX86CallA, kCall, IS_QUAD_OP | IS_BRANCH | IS_LOAD, { 0, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallA", "[!0r+!1r<<!2d+!3d]" },
301 { kX86CallT, kCall, IS_UNARY_OP | IS_BRANCH | IS_LOAD, { THREAD_PREFIX, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallT", "fs:[!0d]" },
302 { kX86Ret, kNullary,NO_OPERAND | IS_BRANCH, { 0, 0, 0xC3, 0, 0, 0, 0, 0 }, "Ret", "" },
buzbeee88dfbf2012-03-05 11:19:57 -0800303};
304
Ian Rogersb5d09b22012-03-06 22:14:17 -0800305static size_t computeSize(X86EncodingMap* entry, int displacement, bool has_sib) {
306 size_t size = 0;
307 if (entry->skeleton.prefix1 > 0) {
308 ++size;
309 if (entry->skeleton.prefix2 > 0) {
310 ++size;
Ian Rogersde797832012-03-06 10:18:10 -0800311 }
Ian Rogersde797832012-03-06 10:18:10 -0800312 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800313 ++size; // opcode
314 if (entry->skeleton.opcode == 0x0F) {
315 ++size;
316 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
317 ++size;
318 }
319 }
320 ++size; // modrm
321 if (has_sib) {
322 ++size;
323 }
324 if (displacement != 0) {
325 if (entry->opcode != kX86Lea32RA) {
326 DCHECK_NE(entry->flags & (IS_LOAD | IS_STORE), 0);
327 }
328 size += IS_SIMM8(displacement) ? 1 : 4;
329 }
330 size += entry->skeleton.immediate_bytes;
331 return size;
332}
333
334int oatGetInsnSize(LIR* lir) {
335 X86EncodingMap* entry = &EncodingMap[lir->opcode];
336 switch (entry->kind) {
337 case kData:
338 return 4; // 4 bytes of data
339 case kNop:
340 return lir->operands[0]; // length of nop is sole operand
341 case kNullary:
342 return 1; // 1 byte of opcode
343 case kReg: // lir operands - 0: reg
344 return computeSize(entry, 0, false);
345 case kMem: { // lir operands - 0: base, 1: disp
346 int base = lir->operands[0];
347 // SP requires a special extra SIB byte
348 return computeSize(entry, lir->operands[1], false) + (base == rSP ? 1 : 0);
349 }
350 case kArray: // lir operands - 0: base, 1: index, 2: scale, 3: disp
351 return computeSize(entry, lir->operands[3], true);
352 case kMemReg: { // lir operands - 0: base, 1: disp, 2: reg
353 int base = lir->operands[0];
354 // SP requires a special extra SIB byte
355 return computeSize(entry, lir->operands[1], false) + (base == rSP ? 1 : 0);
356 }
357 case kArrayReg: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
358 return computeSize(entry, lir->operands[3], true);
359 case kThreadReg: // lir operands - 0: disp, 1: reg
360 return computeSize(entry, lir->operands[0], false);
361 case kRegReg:
362 return computeSize(entry, 0, false);
363 case kRegMem: { // lir operands - 0: reg, 1: base, 2: disp
364 int base = lir->operands[1];
365 return computeSize(entry, lir->operands[2], false) + (base == rSP ? 1 : 0);
366 }
367 case kRegArray: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp
368 return computeSize(entry, lir->operands[4], true);
369 case kRegThread: // lir operands - 0: reg, 1: disp
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700370 return computeSize(entry, 0x12345678, false); // displacement size is always 32bit
Ian Rogersb5d09b22012-03-06 22:14:17 -0800371 case kRegImm: { // lir operands - 0: reg, 1: immediate
Ian Rogersb41b33b2012-03-20 14:22:54 -0700372 size_t size = computeSize(entry, 0, false);
373 if (entry->skeleton.ax_opcode == 0) {
374 return size;
375 } else {
376 // AX opcodes don't require the modrm byte.
377 int reg = lir->operands[0];
378 return size - (reg == rAX ? 1 : 0);
379 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800380 }
381 case kMemImm: // lir operands - 0: base, 1: disp, 2: immediate
382 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
383 return computeSize(entry, lir->operands[1], false);
384 case kArrayImm: // lir operands - 0: base, 1: index, 2: scale, 3: disp 4: immediate
385 return computeSize(entry, lir->operands[3], true);
386 case kThreadImm: // lir operands - 0: disp, 1: imm
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700387 return computeSize(entry, 0x12345678, false); // displacement size is always 32bit
Ian Rogersb5d09b22012-03-06 22:14:17 -0800388 case kRegRegImm: // lir operands - 0: reg, 1: reg, 2: imm
389 return computeSize(entry, 0, false);
390 case kRegMemImm: // lir operands - 0: reg, 1: base, 2: disp, 3: imm
391 CHECK_NE(lir->operands[1], static_cast<int>(rSP)); // TODO: add extra SIB byte
392 return computeSize(entry, lir->operands[2], false);
393 case kRegArrayImm: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp, 5: imm
394 return computeSize(entry, lir->operands[4], true);
395 case kMovRegImm: // lir operands - 0: reg, 1: immediate
396 return 1 + entry->skeleton.immediate_bytes;
397 case kShiftRegImm: // lir operands - 0: reg, 1: immediate
398 // Shift by immediate one has a shorter opcode.
399 return computeSize(entry, 0, false) - (lir->operands[1] == 1 ? 1 : 0);
400 case kShiftMemImm: // lir operands - 0: base, 1: disp, 2: immediate
401 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
402 // Shift by immediate one has a shorter opcode.
403 return computeSize(entry, lir->operands[1], false) - (lir->operands[2] == 1 ? 1 : 0);
404 case kShiftArrayImm: // lir operands - 0: base, 1: index, 2: scale, 3: disp 4: immediate
405 // Shift by immediate one has a shorter opcode.
406 return computeSize(entry, lir->operands[3], true) - (lir->operands[4] == 1 ? 1 : 0);
407 case kShiftRegCl:
408 return computeSize(entry, 0, false);
409 case kShiftMemCl: // lir operands - 0: base, 1: disp, 2: cl
410 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
411 return computeSize(entry, lir->operands[1], false);
412 case kShiftArrayCl: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
413 return computeSize(entry, lir->operands[3], true);
414 case kRegCond: // lir operands - 0: reg, 1: cond
415 return computeSize(entry, 0, false);
416 case kMemCond: // lir operands - 0: base, 1: disp, 2: cond
417 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
418 return computeSize(entry, lir->operands[1], false);
419 case kArrayCond: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: cond
420 return computeSize(entry, lir->operands[3], true);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700421 case kJcc:
422 if (lir->opcode == kX86Jcc8) {
423 return 2; // opcode + rel8
424 } else {
425 DCHECK(lir->opcode == kX86Jcc32);
426 return 6; // 2 byte opcode + rel32
427 }
428 case kJmp:
429 if (lir->opcode == kX86Jmp8) {
430 return 2; // opcode + rel8
431 } else {
432 DCHECK(lir->opcode == kX86Jmp32);
433 return 5; // opcode + rel32
434 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800435 case kCall:
436 switch(lir->opcode) {
437 case kX86CallR: return 2; // opcode modrm
438 case kX86CallM: // lir operands - 0: base, 1: disp
439 return computeSize(entry, lir->operands[1], false);
440 case kX86CallA: // lir operands - 0: base, 1: index, 2: scale, 3: disp
441 return computeSize(entry, lir->operands[3], true);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700442 case kX86CallT: // lir operands - 0: disp
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700443 return computeSize(entry, 0x12345678, false); // displacement size is always 32bit
Ian Rogersb5d09b22012-03-06 22:14:17 -0800444 default:
445 break;
446 }
447 break;
448 default:
449 break;
450 }
451 UNIMPLEMENTED(FATAL) << "Unimplemented size encoding for: " << entry->name;
Ian Rogersde797832012-03-06 10:18:10 -0800452 return 0;
453}
buzbeee88dfbf2012-03-05 11:19:57 -0800454
Ian Rogersb5d09b22012-03-06 22:14:17 -0800455static uint8_t modrmForDisp(int disp) {
456 if (disp == 0) {
457 return 0;
458 } else if (IS_SIMM8(disp)) {
459 return 1;
460 } else {
461 return 2;
462 }
463}
464
465static void emitDisp(CompilationUnit* cUnit, int disp) {
466 if (disp == 0) {
467 return;
468 } else if (IS_SIMM8(disp)) {
469 cUnit->codeBuffer.push_back(disp & 0xFF);
470 } else {
471 cUnit->codeBuffer.push_back(disp & 0xFF);
472 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
473 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
474 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
475 }
476}
477
478static void emitOpReg(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t reg) {
479 if (entry->skeleton.prefix1 != 0) {
480 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
481 if (entry->skeleton.prefix2 != 0) {
482 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
483 }
484 } else {
485 DCHECK_EQ(0, entry->skeleton.prefix2);
486 }
487 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
488 if (entry->skeleton.opcode == 0x0F) {
489 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
490 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
491 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
492 } else {
493 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
494 }
495 } else {
496 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
497 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
498 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700499 if (FPREG(reg)) {
500 reg = reg & FP_REG_MASK;
501 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800502 DCHECK_LT(reg, 8);
503 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
504 cUnit->codeBuffer.push_back(modrm);
505 DCHECK_EQ(0, entry->skeleton.ax_opcode);
506 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
507}
508
509static void emitOpMem(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t base, int disp) {
510 if (entry->skeleton.prefix1 != 0) {
511 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
512 if (entry->skeleton.prefix2 != 0) {
513 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
514 }
515 } else {
516 DCHECK_EQ(0, entry->skeleton.prefix2);
517 }
518 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
519 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
520 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
521 DCHECK_LT(entry->skeleton.modrm_opcode, 8);
522 DCHECK_LT(base, 8);
523 uint8_t modrm = (modrmForDisp(disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
524 cUnit->codeBuffer.push_back(modrm);
525 emitDisp(cUnit, disp);
526 DCHECK_EQ(0, entry->skeleton.ax_opcode);
527 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
528}
529
530static void emitMemReg(CompilationUnit* cUnit, const X86EncodingMap* entry,
531 uint8_t base, int disp, uint8_t reg) {
532 if (entry->skeleton.prefix1 != 0) {
533 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
534 if (entry->skeleton.prefix2 != 0) {
535 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
536 }
537 } else {
538 DCHECK_EQ(0, entry->skeleton.prefix2);
539 }
540 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
541 if (entry->skeleton.opcode == 0x0F) {
542 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
543 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
544 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
545 } else {
546 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
547 }
548 } else {
549 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
550 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
551 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700552 if (FPREG(reg)) {
553 reg = reg & FP_REG_MASK;
554 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800555 DCHECK_LT(reg, 8);
556 DCHECK_LT(base, 8);
557 uint8_t modrm = (modrmForDisp(disp) << 6) | (reg << 3) | base;
558 cUnit->codeBuffer.push_back(modrm);
559 if (base == rSP) {
560 // Special SIB for SP base
561 cUnit->codeBuffer.push_back(0 << 6 | (rSP << 3) | rSP);
562 }
563 emitDisp(cUnit, disp);
564 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
565 DCHECK_EQ(0, entry->skeleton.ax_opcode);
566 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
567}
568
569static void emitRegMem(CompilationUnit* cUnit, const X86EncodingMap* entry,
570 uint8_t reg, uint8_t base, int disp) {
571 // Opcode will flip operands.
572 emitMemReg(cUnit, entry, base, disp, reg);
573}
574
575static void emitRegArray(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t reg,
576 uint8_t base, uint8_t index, int scale, int disp) {
577 if (entry->skeleton.prefix1 != 0) {
578 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
579 if (entry->skeleton.prefix2 != 0) {
580 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
581 }
582 } else {
583 DCHECK_EQ(0, entry->skeleton.prefix2);
584 }
585 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
586 if (entry->skeleton.opcode == 0x0F) {
587 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
588 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
589 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
590 } else {
591 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
592 }
593 } else {
594 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
595 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
596 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700597 if (FPREG(reg)) {
598 reg = reg & FP_REG_MASK;
599 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800600 DCHECK_LT(reg, 8);
601 uint8_t modrm = (modrmForDisp(disp) << 6) | (reg << 3) | rSP;
602 cUnit->codeBuffer.push_back(modrm);
603 DCHECK_LT(scale, 4);
604 DCHECK_LT(index, 8);
605 DCHECK_LT(base, 8);
606 uint8_t sib = (scale << 6) | (index << 3) | base;
607 cUnit->codeBuffer.push_back(sib);
608 emitDisp(cUnit, disp);
609 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
610 DCHECK_EQ(0, entry->skeleton.ax_opcode);
611 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
612}
613
Ian Rogersb41b33b2012-03-20 14:22:54 -0700614static void emitArrayReg(CompilationUnit* cUnit, const X86EncodingMap* entry,
615 uint8_t base, uint8_t index, int scale, int disp, uint8_t reg) {
616 // Opcode will flip operands.
617 emitRegArray(cUnit, entry, reg, base, index, scale, disp);
618}
619
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700620static void emitRegThread(CompilationUnit* cUnit, const X86EncodingMap* entry,
621 uint8_t reg, int disp) {
622 DCHECK_NE(entry->skeleton.prefix1, 0);
623 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
624 if (entry->skeleton.prefix2 != 0) {
625 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
626 }
627 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
628 if (entry->skeleton.opcode == 0x0F) {
629 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
630 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
631 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
632 } else {
633 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
634 }
635 } else {
636 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
637 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
638 }
639 if (FPREG(reg)) {
640 reg = reg & FP_REG_MASK;
641 }
642 DCHECK_LT(reg, 8);
643 uint8_t modrm = (0 << 6) | (reg << 3) | rBP;
644 cUnit->codeBuffer.push_back(modrm);
645 cUnit->codeBuffer.push_back(disp & 0xFF);
646 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
647 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
648 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
649 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
650 DCHECK_EQ(0, entry->skeleton.ax_opcode);
651 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
652}
653
Ian Rogersb5d09b22012-03-06 22:14:17 -0800654static void emitRegReg(CompilationUnit* cUnit, const X86EncodingMap* entry,
655 uint8_t reg1, uint8_t reg2) {
656 if (entry->skeleton.prefix1 != 0) {
657 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
658 if (entry->skeleton.prefix2 != 0) {
659 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
660 }
661 } else {
662 DCHECK_EQ(0, entry->skeleton.prefix2);
663 }
664 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
665 if (entry->skeleton.opcode == 0x0F) {
666 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
667 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
668 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
669 } else {
670 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
671 }
672 } else {
673 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
674 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
675 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700676 if (FPREG(reg1)) {
677 reg1 = reg1 & FP_REG_MASK;
678 }
679 if (FPREG(reg2)) {
680 reg2 = reg2 & FP_REG_MASK;
681 }
682 DCHECK_LT(reg1, 8);
683 DCHECK_LT(reg2, 8);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800684 uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
685 cUnit->codeBuffer.push_back(modrm);
686 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
687 DCHECK_EQ(0, entry->skeleton.ax_opcode);
688 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
689}
690
691static void emitRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
692 uint8_t reg, int imm) {
693 if (entry->skeleton.prefix1 != 0) {
694 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
695 if (entry->skeleton.prefix2 != 0) {
696 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
697 }
698 } else {
699 DCHECK_EQ(0, entry->skeleton.prefix2);
700 }
701 if (reg == rAX && entry->skeleton.ax_opcode != 0) {
702 cUnit->codeBuffer.push_back(entry->skeleton.ax_opcode);
703 } else {
704 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
705 if (entry->skeleton.opcode == 0x0F) {
706 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
707 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
708 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
709 } else {
710 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
711 }
712 } else {
713 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
714 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
715 }
716 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
717 cUnit->codeBuffer.push_back(modrm);
718 }
719 switch (entry->skeleton.immediate_bytes) {
720 case 1:
721 DCHECK(IS_SIMM8(imm));
722 cUnit->codeBuffer.push_back(imm & 0xFF);
723 break;
724 case 2:
725 DCHECK(IS_SIMM16(imm));
726 cUnit->codeBuffer.push_back(imm & 0xFF);
727 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
728 break;
729 case 4:
730 cUnit->codeBuffer.push_back(imm & 0xFF);
731 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
732 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
733 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
734 break;
735 default:
736 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
737 << ") for instruction: " << entry->name;
738 break;
739 }
740}
741
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700742static void emitThreadImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
743 int disp, int imm) {
744 if (entry->skeleton.prefix1 != 0) {
745 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
746 if (entry->skeleton.prefix2 != 0) {
747 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
748 }
749 } else {
750 DCHECK_EQ(0, entry->skeleton.prefix2);
751 }
752 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
753 if (entry->skeleton.opcode == 0x0F) {
754 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
755 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
756 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
757 } else {
758 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
759 }
760 } else {
761 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
762 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
763 }
764 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
765 cUnit->codeBuffer.push_back(modrm);
766 cUnit->codeBuffer.push_back(disp & 0xFF);
767 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
768 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
769 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
770 switch (entry->skeleton.immediate_bytes) {
771 case 1:
772 DCHECK(IS_SIMM8(imm));
773 cUnit->codeBuffer.push_back(imm & 0xFF);
774 break;
775 case 2:
776 DCHECK(IS_SIMM16(imm));
777 cUnit->codeBuffer.push_back(imm & 0xFF);
778 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
779 break;
780 case 4:
781 cUnit->codeBuffer.push_back(imm & 0xFF);
782 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
783 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
784 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
785 break;
786 default:
787 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
788 << ") for instruction: " << entry->name;
789 break;
790 }
791 DCHECK_EQ(entry->skeleton.ax_opcode, 0);
792}
793
794static void emitMovRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
795 uint8_t reg, int imm) {
796 DCHECK_LT(reg, 8);
797 cUnit->codeBuffer.push_back(0xB8 + reg);
798 cUnit->codeBuffer.push_back(imm & 0xFF);
799 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
800 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
801 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
802}
803
Ian Rogersb41b33b2012-03-20 14:22:54 -0700804static void emitShiftRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
805 uint8_t reg, int imm) {
806 if (entry->skeleton.prefix1 != 0) {
807 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
808 if (entry->skeleton.prefix2 != 0) {
809 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
810 }
811 } else {
812 DCHECK_EQ(0, entry->skeleton.prefix2);
813 }
814 if (imm != 1) {
815 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
816 } else {
817 // Shorter encoding for 1 bit shift
818 cUnit->codeBuffer.push_back(entry->skeleton.ax_opcode);
819 }
820 if (entry->skeleton.opcode == 0x0F) {
821 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
822 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
823 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
824 } else {
825 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
826 }
827 } else {
828 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
829 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
830 }
831 DCHECK_LT(reg, 8);
832 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
833 cUnit->codeBuffer.push_back(modrm);
834 if (imm != 1) {
835 DCHECK_EQ(entry->skeleton.immediate_bytes, 1);
836 DCHECK(IS_SIMM8(imm));
837 cUnit->codeBuffer.push_back(imm & 0xFF);
838 }
839}
840
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700841static void emitJmp(CompilationUnit* cUnit, const X86EncodingMap* entry, int rel) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700842 if (entry->opcode == kX86Jmp8) {
843 DCHECK(IS_SIMM8(rel));
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700844 cUnit->codeBuffer.push_back(0xEB);
845 cUnit->codeBuffer.push_back(rel & 0xFF);
846 } else {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700847 DCHECK(entry->opcode == kX86Jmp32);
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700848 cUnit->codeBuffer.push_back(0xE9);
849 cUnit->codeBuffer.push_back(rel & 0xFF);
850 cUnit->codeBuffer.push_back((rel >> 8) & 0xFF);
851 cUnit->codeBuffer.push_back((rel >> 16) & 0xFF);
852 cUnit->codeBuffer.push_back((rel >> 24) & 0xFF);
853 }
854}
855
856static void emitJcc(CompilationUnit* cUnit, const X86EncodingMap* entry,
857 int rel, uint8_t cc) {
858 DCHECK_LT(cc, 16);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700859 if (entry->opcode == kX86Jcc8) {
860 DCHECK(IS_SIMM8(rel));
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700861 cUnit->codeBuffer.push_back(0x70 | cc);
862 cUnit->codeBuffer.push_back(rel & 0xFF);
863 } else {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700864 DCHECK(entry->opcode == kX86Jcc32);
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700865 cUnit->codeBuffer.push_back(0x0F);
866 cUnit->codeBuffer.push_back(0x80 | cc);
867 cUnit->codeBuffer.push_back(rel & 0xFF);
868 cUnit->codeBuffer.push_back((rel >> 8) & 0xFF);
869 cUnit->codeBuffer.push_back((rel >> 16) & 0xFF);
870 cUnit->codeBuffer.push_back((rel >> 24) & 0xFF);
871 }
872}
873
874static void emitCallMem(CompilationUnit* cUnit, const X86EncodingMap* entry,
875 uint8_t base, int disp) {
876 if (entry->skeleton.prefix1 != 0) {
877 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
878 if (entry->skeleton.prefix2 != 0) {
879 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
880 }
881 } else {
882 DCHECK_EQ(0, entry->skeleton.prefix2);
883 }
884 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
885 if (entry->skeleton.opcode == 0x0F) {
886 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
887 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
888 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
889 } else {
890 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
891 }
892 } else {
893 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
894 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
895 }
896 uint8_t modrm = (modrmForDisp(disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
897 cUnit->codeBuffer.push_back(modrm);
898 if (base == rSP) {
899 // Special SIB for SP base
900 cUnit->codeBuffer.push_back(0 << 6 | (rSP << 3) | rSP);
901 }
902 emitDisp(cUnit, disp);
903 DCHECK_EQ(0, entry->skeleton.ax_opcode);
904 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
905}
906
907static void emitCallThread(CompilationUnit* cUnit, const X86EncodingMap* entry, int disp) {
908 DCHECK_NE(entry->skeleton.prefix1, 0);
909 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
910 if (entry->skeleton.prefix2 != 0) {
911 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
912 }
913 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
914 if (entry->skeleton.opcode == 0x0F) {
915 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
916 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
917 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
918 } else {
919 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
920 }
921 } else {
922 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
923 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
924 }
925 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
926 cUnit->codeBuffer.push_back(modrm);
927 cUnit->codeBuffer.push_back(disp & 0xFF);
928 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
929 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
930 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
931 DCHECK_EQ(0, entry->skeleton.ax_opcode);
932 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
933}
934
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700935void emitUnimplemented(CompilationUnit* cUnit, const X86EncodingMap* entry, LIR* lir) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700936 UNIMPLEMENTED(WARNING) << "encoding for: " << entry->name;
Ian Rogers141b0c72012-03-15 18:18:52 -0700937 for (int i = 0; i < oatGetInsnSize(lir); ++i) {
938 cUnit->codeBuffer.push_back(0xCC); // push breakpoint instruction - int 3
939 }
940}
941
buzbeee88dfbf2012-03-05 11:19:57 -0800942/*
943 * Assemble the LIR into binary instruction format. Note that we may
944 * discover that pc-relative displacements may not fit the selected
945 * instruction. In those cases we will try to substitute a new code
946 * sequence or request that the trace be shortened and retried.
947 */
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700948AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800949 LIR *lir;
950 AssemblerStatus res = kSuccess; // Assume success
buzbeee88dfbf2012-03-05 11:19:57 -0800951
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700952 const bool kVerbosePcFixup = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800953 for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
954 if (lir->opcode < 0) {
955 continue;
buzbeee88dfbf2012-03-05 11:19:57 -0800956 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800957
Ian Rogersb5d09b22012-03-06 22:14:17 -0800958 if (lir->flags.isNop) {
959 continue;
960 }
961
962 if (lir->flags.pcRelFixup) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700963 switch (lir->opcode) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700964 case kX86Jcc8: {
965 LIR *targetLIR = lir->target;
966 DCHECK(targetLIR != NULL);
967 int delta = 0;
968 intptr_t pc;
969 if (IS_SIMM8(lir->operands[0])) {
970 pc = lir->offset + 2 /* opcode + rel8 */;
971 } else {
972 pc = lir->offset + 6 /* 2 byte opcode + rel32 */;
973 }
974 intptr_t target = targetLIR->offset;
975 delta = target - pc;
976 if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) {
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700977 if (kVerbosePcFixup) {
978 LOG(INFO) << "Retry for JCC growth at " << lir->offset
979 << " delta: " << delta << " old delta: " << lir->operands[0];
980 }
Ian Rogersb41b33b2012-03-20 14:22:54 -0700981 lir->opcode = kX86Jcc32;
982 oatSetupResourceMasks(lir);
983 res = kRetryAll;
984 }
985 lir->operands[0] = delta;
986 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700987 }
Ian Rogersb41b33b2012-03-20 14:22:54 -0700988 case kX86Jmp8: {
989 LIR *targetLIR = lir->target;
990 DCHECK(targetLIR != NULL);
991 int delta = 0;
992 intptr_t pc;
993 if (IS_SIMM8(lir->operands[0])) {
994 pc = lir->offset + 2 /* opcode + rel8 */;
995 } else {
996 pc = lir->offset + 5 /* opcode + rel32 */;
997 }
998 intptr_t target = targetLIR->offset;
999 delta = target - pc;
1000 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && lir->operands[0] == 0) {
1001 // Useless branch
1002 lir->flags.isNop = true;
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001003 if (kVerbosePcFixup) {
1004 LOG(INFO) << "Retry for useless branch at " << lir->offset;
1005 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001006 res = kRetryAll;
1007 } else if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) {
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001008 if (kVerbosePcFixup) {
1009 LOG(INFO) << "Retry for JMP growth at " << lir->offset;
1010 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001011 lir->opcode = kX86Jmp32;
1012 oatSetupResourceMasks(lir);
1013 res = kRetryAll;
1014 }
1015 lir->operands[0] = delta;
1016 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001017 }
1018 default:
1019 break;
1020 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001021 }
1022
1023 /*
1024 * If one of the pc-relative instructions expanded we'll have
1025 * to make another pass. Don't bother to fully assemble the
1026 * instruction.
1027 */
1028 if (res != kSuccess) {
1029 continue;
1030 }
1031 const X86EncodingMap *entry = &EncodingMap[lir->opcode];
Ian Rogers141b0c72012-03-15 18:18:52 -07001032 size_t starting_cbuf_size = cUnit->codeBuffer.size();
Ian Rogersb5d09b22012-03-06 22:14:17 -08001033 switch(entry->kind) {
1034 case kData: // 4 bytes of data
1035 cUnit->codeBuffer.push_back(lir->operands[0]);
1036 break;
1037 case kNullary: // 1 byte of opcode
1038 DCHECK_EQ(0, entry->skeleton.prefix1);
1039 DCHECK_EQ(0, entry->skeleton.prefix2);
1040 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001041 if (entry->skeleton.extra_opcode1 != 0) {
1042 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
1043 if (entry->skeleton.extra_opcode2 != 0) {
1044 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
1045 }
1046 } else {
1047 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1048 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001049 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
1050 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1051 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1052 break;
1053 case kReg: // lir operands - 0: reg
1054 emitOpReg(cUnit, entry, lir->operands[0]);
1055 break;
1056 case kMem: // lir operands - 0: base, 1: disp
1057 emitOpMem(cUnit, entry, lir->operands[0], lir->operands[1]);
1058 break;
1059 case kMemReg: // lir operands - 0: base, 1: disp, 2: reg
1060 emitMemReg(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1061 break;
Ian Rogersb41b33b2012-03-20 14:22:54 -07001062 case kArrayReg: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
1063 emitArrayReg(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1064 lir->operands[3], lir->operands[4]);
1065 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001066 case kRegMem: // lir operands - 0: reg, 1: base, 2: disp
1067 emitRegMem(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1068 break;
1069 case kRegArray: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp
1070 emitRegArray(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1071 lir->operands[3], lir->operands[4]);
1072 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001073 case kRegThread: // lir operands - 0: reg, 1: disp
1074 emitRegThread(cUnit, entry, lir->operands[0], lir->operands[1]);
1075 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001076 case kRegReg: // lir operands - 0: reg1, 1: reg2
1077 emitRegReg(cUnit, entry, lir->operands[0], lir->operands[1]);
1078 break;
1079 case kRegImm: // lir operands - 0: reg, 1: immediate
1080 emitRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1081 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001082 case kThreadImm: // lir operands - 0: disp, 1: immediate
1083 emitThreadImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1084 break;
1085 case kMovRegImm: // lir operands - 0: reg, 1: immediate
1086 emitMovRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1087 break;
Ian Rogersb41b33b2012-03-20 14:22:54 -07001088 case kShiftRegImm: // lir operands - 0: reg, 1: immediate
1089 emitShiftRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1090 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001091 case kJmp: // lir operands - 0: rel
1092 emitJmp(cUnit, entry, lir->operands[0]);
1093 break;
1094 case kJcc: // lir operands - 0: rel, 1: CC, target assigned
1095 emitJcc(cUnit, entry, lir->operands[0], lir->operands[1]);
1096 break;
1097 case kCall:
1098 switch(entry->opcode) {
1099 case kX86CallM: // lir operands - 0: base, 1: disp
1100 emitCallMem(cUnit, entry, lir->operands[0], lir->operands[1]);
1101 break;
1102 case kX86CallT: // lir operands - 0: disp
1103 emitCallThread(cUnit, entry, lir->operands[0]);
1104 break;
1105 default:
1106 emitUnimplemented(cUnit, entry, lir);
1107 break;
1108 }
1109 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001110 default:
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001111 emitUnimplemented(cUnit, entry, lir);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001112 break;
1113 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001114 if (entry->kind != kJcc && entry->kind != kJmp) {
1115 CHECK_EQ(static_cast<size_t>(oatGetInsnSize(lir)),
1116 cUnit->codeBuffer.size() - starting_cbuf_size)
1117 << "Instruction size mismatch for entry: " << EncodingMap[lir->opcode].name;
1118 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001119 }
1120 return res;
buzbeee88dfbf2012-03-05 11:19:57 -08001121}
1122
buzbeee88dfbf2012-03-05 11:19:57 -08001123/*
1124 * Target-dependent offset assignment.
1125 * independent.
1126 */
1127int oatAssignInsnOffsets(CompilationUnit* cUnit)
1128{
1129 LIR* x86LIR;
1130 int offset = 0;
1131
1132 for (x86LIR = (LIR *) cUnit->firstLIRInsn;
1133 x86LIR;
1134 x86LIR = NEXT_LIR(x86LIR)) {
1135 x86LIR->offset = offset;
1136 if (x86LIR->opcode >= 0) {
1137 if (!x86LIR->flags.isNop) {
1138 offset += x86LIR->flags.size;
1139 }
1140 } else if (x86LIR->opcode == kPseudoPseudoAlign4) {
1141 if (offset & 0x2) {
1142 offset += 2;
1143 x86LIR->operands[0] = 1;
1144 } else {
1145 x86LIR->operands[0] = 0;
1146 }
1147 }
1148 /* Pseudo opcodes don't consume space */
1149 }
1150
1151 return offset;
1152}
1153
1154} // namespace art