blob: bad7142522090f12ef2bf72e83395ee7355812a0 [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" },
Ian Rogers7caad772012-03-30 01:07:54 -070029 { kX86Bkpt, kNullary, NO_OPERAND | IS_BRANCH, { 0, 0, 0xCC, 0, 0, 0, 0, 0 }, "int 3", "" },
Ian Rogersb5d09b22012-03-06 22:14:17 -080030 { 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" }, \
Ian Rogers7caad772012-03-30 01:07:54 -0700200{ kX86 ## opname ## 32RC, kShiftRegCl, IS_BINARY_OP | SETS_CCODES, { 0, 0, 0xD3, 0, 0, modrm_opcode, 0, 0 }, #opname "32RC", "" }, \
201{ kX86 ## opname ## 32MC, kShiftMemCl, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0xD3, 0, 0, modrm_opcode, 0, 0 }, #opname "32MC", "" }, \
202{ kX86 ## opname ## 32AC, kShiftArrayCl, IS_QUIN_OP | SETS_CCODES, { 0, 0, 0xD3, 0, 0, modrm_opcode, 0, 0 }, #opname "32AC", "" }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800203
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),
Ian Rogers7caad772012-03-30 01:07:54 -0700209 SHIFT_ENCODING_MAP(Shr, 0x5),
Ian Rogersb5d09b22012-03-06 22:14:17 -0800210 SHIFT_ENCODING_MAP(Sar, 0x7),
211#undef SHIFT_ENCODING_MAP
212
213#define UNARY_ENCODING_MAP(opname, modrm, \
214 reg, reg_kind, reg_flags, \
215 mem, mem_kind, mem_flags, \
216 arr, arr_kind, arr_flags, imm) \
217{ kX86 ## opname ## 8 ## reg, reg_kind, reg_flags, { 0, 0, 0xF6, 0, 0, modrm, 0, imm << 0}, #opname "8" #reg, "" }, \
218{ kX86 ## opname ## 8 ## mem, mem_kind, IS_LOAD | mem_flags, { 0, 0, 0xF6, 0, 0, modrm, 0, imm << 0}, #opname "8" #mem, "" }, \
219{ kX86 ## opname ## 8 ## arr, arr_kind, IS_LOAD | arr_flags, { 0, 0, 0xF6, 0, 0, modrm, 0, imm << 0}, #opname "8" #arr, "" }, \
220{ kX86 ## opname ## 16 ## reg, reg_kind, reg_flags, { 0x66, 0, 0xF7, 0, 0, modrm, 0, imm << 1}, #opname "16" #reg, "" }, \
221{ kX86 ## opname ## 16 ## mem, mem_kind, IS_LOAD | mem_flags, { 0x66, 0, 0xF7, 0, 0, modrm, 0, imm << 1}, #opname "16" #mem, "" }, \
222{ kX86 ## opname ## 16 ## arr, arr_kind, IS_LOAD | arr_flags, { 0x66, 0, 0xF7, 0, 0, modrm, 0, imm << 1}, #opname "16" #arr, "" }, \
223{ kX86 ## opname ## 32 ## reg, reg_kind, reg_flags, { 0, 0, 0xF7, 0, 0, modrm, 0, imm << 2}, #opname "32" #reg, "" }, \
224{ kX86 ## opname ## 32 ## mem, mem_kind, IS_LOAD | mem_flags, { 0, 0, 0xF7, 0, 0, modrm, 0, imm << 2}, #opname "32" #mem, "" }, \
225{ kX86 ## opname ## 32 ## arr, arr_kind, IS_LOAD | arr_flags, { 0, 0, 0xF7, 0, 0, modrm, 0, imm << 2}, #opname "32" #arr, "" }
226
227 UNARY_ENCODING_MAP(Test, 0x0, RI, kRegImm, IS_BINARY_OP, MI, kMemImm, IS_TERTIARY_OP, AI, kArrayImm, IS_QUIN_OP, 1),
228 UNARY_ENCODING_MAP(Not, 0x2, R, kReg, IS_UNARY_OP, M, kMem, IS_BINARY_OP, A, kArray, IS_QUAD_OP, 0),
229 UNARY_ENCODING_MAP(Neg, 0x3, R, kReg, IS_UNARY_OP, M, kMem, IS_BINARY_OP, A, kArray, IS_QUAD_OP, 0),
230 UNARY_ENCODING_MAP(Mul, 0x4, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
231 UNARY_ENCODING_MAP(Imul, 0x5, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
232 UNARY_ENCODING_MAP(Divmod, 0x6, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
233 UNARY_ENCODING_MAP(Idivmod, 0x7, DaR, kRegRegReg, IS_TERTIARY_OP, DaM, kRegRegMem, IS_QUAD_OP, DaA, kRegRegArray, IS_SEXTUPLE_OP, 0),
234#undef UNARY_ENCODING_MAP
235
236#define EXT_0F_ENCODING_MAP(opname, prefix, opcode) \
237{ kX86 ## opname ## RR, kRegReg, IS_BINARY_OP, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \
238{ kX86 ## opname ## RM, kRegMem, IS_LOAD | IS_TERTIARY_OP, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RM", "!0r,[!1r+!2d]" }, \
239{ kX86 ## opname ## RA, kRegArray, IS_LOAD | IS_QUIN_OP, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RA", "!0r,[!1r+!2r<<!3d+!4d]" }
240
241 EXT_0F_ENCODING_MAP(Movsd, 0xF2, 0x10),
242 { kX86MovsdMR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0xF2, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovsdMR", "[!0r+!1d],!2r" },
243 { kX86MovsdAR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0xF2, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovsdAR", "[!0r+!1r<<!2d+!3d],!4r" },
244
245 EXT_0F_ENCODING_MAP(Movss, 0xF3, 0x10),
246 { kX86MovssMR, kMemReg, IS_STORE | IS_TERTIARY_OP, { 0xF3, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovssMR", "[!0r+!1d],!2r" },
247 { kX86MovssAR, kArrayReg, IS_STORE | IS_QUIN_OP, { 0xF3, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovssAR", "[!0r+!1r<<!2d+!3d],!4r" },
248
249 EXT_0F_ENCODING_MAP(Cvtsi2sd, 0xF2, 0x2A),
250 EXT_0F_ENCODING_MAP(Cvtsi2ss, 0xF3, 0x2A),
251 EXT_0F_ENCODING_MAP(Cvttsd2si, 0xF2, 0x2C),
252 EXT_0F_ENCODING_MAP(Cvttss2si, 0xF3, 0x2C),
253 EXT_0F_ENCODING_MAP(Cvtsd2si, 0xF2, 0x2D),
254 EXT_0F_ENCODING_MAP(Cvtss2si, 0xF3, 0x2D),
255 EXT_0F_ENCODING_MAP(Ucomisd, 0x66, 0x2E),
256 EXT_0F_ENCODING_MAP(Ucomiss, 0x00, 0x2E),
257 EXT_0F_ENCODING_MAP(Comisd, 0x66, 0x2F),
258 EXT_0F_ENCODING_MAP(Comiss, 0x00, 0x2F),
Ian Rogersb41b33b2012-03-20 14:22:54 -0700259 EXT_0F_ENCODING_MAP(Orps, 0x00, 0x56),
260 EXT_0F_ENCODING_MAP(Xorps, 0x00, 0x57),
Ian Rogersb5d09b22012-03-06 22:14:17 -0800261 EXT_0F_ENCODING_MAP(Addsd, 0xF2, 0x58),
262 EXT_0F_ENCODING_MAP(Addss, 0xF3, 0x58),
263 EXT_0F_ENCODING_MAP(Mulsd, 0xF2, 0x59),
264 EXT_0F_ENCODING_MAP(Mulss, 0xF3, 0x59),
265 EXT_0F_ENCODING_MAP(Cvtss2sd, 0xF2, 0x5A),
266 EXT_0F_ENCODING_MAP(Cvtsd2ss, 0xF3, 0x5A),
267 EXT_0F_ENCODING_MAP(Subsd, 0xF2, 0x5C),
268 EXT_0F_ENCODING_MAP(Subss, 0xF3, 0x5C),
269 EXT_0F_ENCODING_MAP(Divsd, 0xF2, 0x5E),
270 EXT_0F_ENCODING_MAP(Divss, 0xF3, 0x5E),
271
Ian Rogersb41b33b2012-03-20 14:22:54 -0700272 { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 7, 0, 1 }, "PsllqRI", "!0r, !1d" },
273
Ian Rogersb5d09b22012-03-06 22:14:17 -0800274 EXT_0F_ENCODING_MAP(Movdxr, 0x66, 0x6E),
275 EXT_0F_ENCODING_MAP(Movdrx, 0x66, 0x7E),
276
277 { kX86Set8R, kRegCond, IS_BINARY_OP, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8R", "!1c !0r" },
278 { kX86Set8M, kMemCond, IS_STORE | IS_TERTIARY_OP, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8M", "!2c [!0r+!1d]" },
279 { kX86Set8A, kArrayCond, IS_STORE | IS_QUIN_OP, { 0, 0, 0x0F, 0x90, 0, 0, 0, 0 }, "Set8A", "!4c [!0r+!1r<<!2d+!3d]" },
280
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700281 // TODO: load/store?
282 // Encode the modrm opcode as an extra opcode byte to avoid computation during assembly.
283 { kX86Mfence, kReg, NO_OPERAND, { 0, 0, 0x0F, 0xAE, 0, 6, 0, 0 }, "Mfence", "" },
284
Ian Rogersb5d09b22012-03-06 22:14:17 -0800285 EXT_0F_ENCODING_MAP(Imul16, 0x66, 0xAF),
286 EXT_0F_ENCODING_MAP(Imul32, 0x00, 0xAF),
287 EXT_0F_ENCODING_MAP(Movzx8, 0x00, 0xB6),
288 EXT_0F_ENCODING_MAP(Movzx16, 0x00, 0xB7),
289 EXT_0F_ENCODING_MAP(Movsx8, 0x00, 0xBE),
290 EXT_0F_ENCODING_MAP(Movsx16, 0x00, 0xBF),
291#undef EXT_0F_ENCODING_MAP
292
Ian Rogersb41b33b2012-03-20 14:22:54 -0700293 { kX86Jcc8, kJcc, IS_BINARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0x70, 0, 0, 0, 0, 0 }, "Jcc8", "!1c !0t" },
294 { kX86Jcc32, kJcc, IS_BINARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0x0F, 0x80, 0, 0, 0, 0 }, "Jcc32", "!1c !0t" },
295 { kX86Jmp8, kJmp, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0xEB, 0, 0, 0, 0, 0 }, "Jmp8", "!0t" },
296 { kX86Jmp32, kJmp, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0xE9, 0, 0, 0, 0, 0 }, "Jmp32", "!0t" },
Ian Rogers7caad772012-03-30 01:07:54 -0700297 { kX86JmpR, kJmp, IS_UNARY_OP | IS_BRANCH, { 0, 0, 0xFF, 0, 0, 4, 0, 0 }, "JmpR", "!0r" },
298 { 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", "" },
303
304 { kX86StartOfMethod, kMacro, IS_UNARY_OP | SETS_CCODES, { 0,0,0,0,0,0,0,0 }, "StartOfMethod", "!0r" },
305 { kX86PcRelLoadRA, kPcRel, IS_LOAD | IS_QUIN_OP, { 0, 0, 0x8B, 0, 0, 0, 0, 0 }, "PcRelLoadRA", "!0r,[!1r+!2r<<!3d+!4p]" },
306 { kX86PcRelAdr, kPcRel, IS_LOAD | IS_BINARY_OP, { 0, 0, 0xB8, 0, 0, 0, 0, 4 }, "PcRelAdr", "!0r,!1d" },
buzbeee88dfbf2012-03-05 11:19:57 -0800307};
308
Ian Rogersb5d09b22012-03-06 22:14:17 -0800309static size_t computeSize(X86EncodingMap* entry, int displacement, bool has_sib) {
310 size_t size = 0;
311 if (entry->skeleton.prefix1 > 0) {
312 ++size;
313 if (entry->skeleton.prefix2 > 0) {
314 ++size;
Ian Rogersde797832012-03-06 10:18:10 -0800315 }
Ian Rogersde797832012-03-06 10:18:10 -0800316 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800317 ++size; // opcode
318 if (entry->skeleton.opcode == 0x0F) {
319 ++size;
320 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
321 ++size;
322 }
323 }
324 ++size; // modrm
325 if (has_sib) {
326 ++size;
327 }
328 if (displacement != 0) {
329 if (entry->opcode != kX86Lea32RA) {
Ian Rogers7caad772012-03-30 01:07:54 -0700330 DCHECK_NE(entry->flags & (IS_LOAD | IS_STORE), 0) << entry->name;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800331 }
332 size += IS_SIMM8(displacement) ? 1 : 4;
333 }
334 size += entry->skeleton.immediate_bytes;
335 return size;
336}
337
338int oatGetInsnSize(LIR* lir) {
339 X86EncodingMap* entry = &EncodingMap[lir->opcode];
340 switch (entry->kind) {
341 case kData:
342 return 4; // 4 bytes of data
343 case kNop:
344 return lir->operands[0]; // length of nop is sole operand
345 case kNullary:
346 return 1; // 1 byte of opcode
347 case kReg: // lir operands - 0: reg
348 return computeSize(entry, 0, false);
349 case kMem: { // lir operands - 0: base, 1: disp
350 int base = lir->operands[0];
351 // SP requires a special extra SIB byte
352 return computeSize(entry, lir->operands[1], false) + (base == rSP ? 1 : 0);
353 }
354 case kArray: // lir operands - 0: base, 1: index, 2: scale, 3: disp
355 return computeSize(entry, lir->operands[3], true);
356 case kMemReg: { // lir operands - 0: base, 1: disp, 2: reg
357 int base = lir->operands[0];
358 // SP requires a special extra SIB byte
359 return computeSize(entry, lir->operands[1], false) + (base == rSP ? 1 : 0);
360 }
361 case kArrayReg: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
362 return computeSize(entry, lir->operands[3], true);
363 case kThreadReg: // lir operands - 0: disp, 1: reg
364 return computeSize(entry, lir->operands[0], false);
365 case kRegReg:
366 return computeSize(entry, 0, false);
367 case kRegMem: { // lir operands - 0: reg, 1: base, 2: disp
368 int base = lir->operands[1];
369 return computeSize(entry, lir->operands[2], false) + (base == rSP ? 1 : 0);
370 }
371 case kRegArray: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp
372 return computeSize(entry, lir->operands[4], true);
373 case kRegThread: // lir operands - 0: reg, 1: disp
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700374 return computeSize(entry, 0x12345678, false); // displacement size is always 32bit
Ian Rogersb5d09b22012-03-06 22:14:17 -0800375 case kRegImm: { // lir operands - 0: reg, 1: immediate
Ian Rogersb41b33b2012-03-20 14:22:54 -0700376 size_t size = computeSize(entry, 0, false);
377 if (entry->skeleton.ax_opcode == 0) {
378 return size;
379 } else {
380 // AX opcodes don't require the modrm byte.
381 int reg = lir->operands[0];
382 return size - (reg == rAX ? 1 : 0);
383 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800384 }
385 case kMemImm: // lir operands - 0: base, 1: disp, 2: immediate
386 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
387 return computeSize(entry, lir->operands[1], false);
388 case kArrayImm: // lir operands - 0: base, 1: index, 2: scale, 3: disp 4: immediate
389 return computeSize(entry, lir->operands[3], true);
390 case kThreadImm: // lir operands - 0: disp, 1: imm
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700391 return computeSize(entry, 0x12345678, false); // displacement size is always 32bit
Ian Rogersb5d09b22012-03-06 22:14:17 -0800392 case kRegRegImm: // lir operands - 0: reg, 1: reg, 2: imm
393 return computeSize(entry, 0, false);
394 case kRegMemImm: // lir operands - 0: reg, 1: base, 2: disp, 3: imm
395 CHECK_NE(lir->operands[1], static_cast<int>(rSP)); // TODO: add extra SIB byte
396 return computeSize(entry, lir->operands[2], false);
397 case kRegArrayImm: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp, 5: imm
398 return computeSize(entry, lir->operands[4], true);
399 case kMovRegImm: // lir operands - 0: reg, 1: immediate
400 return 1 + entry->skeleton.immediate_bytes;
401 case kShiftRegImm: // lir operands - 0: reg, 1: immediate
402 // Shift by immediate one has a shorter opcode.
403 return computeSize(entry, 0, false) - (lir->operands[1] == 1 ? 1 : 0);
404 case kShiftMemImm: // lir operands - 0: base, 1: disp, 2: immediate
405 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
406 // Shift by immediate one has a shorter opcode.
407 return computeSize(entry, lir->operands[1], false) - (lir->operands[2] == 1 ? 1 : 0);
408 case kShiftArrayImm: // lir operands - 0: base, 1: index, 2: scale, 3: disp 4: immediate
409 // Shift by immediate one has a shorter opcode.
410 return computeSize(entry, lir->operands[3], true) - (lir->operands[4] == 1 ? 1 : 0);
411 case kShiftRegCl:
412 return computeSize(entry, 0, false);
413 case kShiftMemCl: // lir operands - 0: base, 1: disp, 2: cl
414 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
415 return computeSize(entry, lir->operands[1], false);
416 case kShiftArrayCl: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
417 return computeSize(entry, lir->operands[3], true);
418 case kRegCond: // lir operands - 0: reg, 1: cond
419 return computeSize(entry, 0, false);
420 case kMemCond: // lir operands - 0: base, 1: disp, 2: cond
421 CHECK_NE(lir->operands[0], static_cast<int>(rSP)); // TODO: add extra SIB byte
422 return computeSize(entry, lir->operands[1], false);
423 case kArrayCond: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: cond
424 return computeSize(entry, lir->operands[3], true);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700425 case kJcc:
426 if (lir->opcode == kX86Jcc8) {
427 return 2; // opcode + rel8
428 } else {
429 DCHECK(lir->opcode == kX86Jcc32);
430 return 6; // 2 byte opcode + rel32
431 }
432 case kJmp:
433 if (lir->opcode == kX86Jmp8) {
434 return 2; // opcode + rel8
Ian Rogers7caad772012-03-30 01:07:54 -0700435 } else if (lir->opcode == kX86Jmp32) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700436 return 5; // opcode + rel32
Ian Rogers7caad772012-03-30 01:07:54 -0700437 } else {
438 DCHECK(lir->opcode == kX86JmpR);
439 return 2; // opcode + modrm
Ian Rogersb41b33b2012-03-20 14:22:54 -0700440 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800441 case kCall:
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700442 switch (lir->opcode) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800443 case kX86CallR: return 2; // opcode modrm
444 case kX86CallM: // lir operands - 0: base, 1: disp
445 return computeSize(entry, lir->operands[1], false);
446 case kX86CallA: // lir operands - 0: base, 1: index, 2: scale, 3: disp
447 return computeSize(entry, lir->operands[3], true);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700448 case kX86CallT: // lir operands - 0: disp
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700449 return computeSize(entry, 0x12345678, false); // displacement size is always 32bit
Ian Rogersb5d09b22012-03-06 22:14:17 -0800450 default:
451 break;
452 }
453 break;
Ian Rogers7caad772012-03-30 01:07:54 -0700454 case kPcRel:
455 if (entry->opcode == kX86PcRelLoadRA) {
456 // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: table
457 return computeSize(entry, 0x12345678, true);
458 } else {
459 DCHECK(entry->opcode == kX86PcRelAdr);
460 return 5; // opcode with reg + 4 byte immediate
461 }
462 case kMacro:
463 DCHECK_EQ(lir->opcode, static_cast<int>(kX86StartOfMethod));
464 return 5 /* call opcode + 4 byte displacement */ + 1 /* pop reg */ +
465 computeSize(&EncodingMap[kX86Sub32RI], 0, false) -
466 (lir->operands[0] == rAX ? 1 : 0); // shorter ax encoding
Ian Rogersb5d09b22012-03-06 22:14:17 -0800467 default:
468 break;
469 }
470 UNIMPLEMENTED(FATAL) << "Unimplemented size encoding for: " << entry->name;
Ian Rogersde797832012-03-06 10:18:10 -0800471 return 0;
472}
buzbeee88dfbf2012-03-05 11:19:57 -0800473
Ian Rogersb5d09b22012-03-06 22:14:17 -0800474static uint8_t modrmForDisp(int disp) {
475 if (disp == 0) {
476 return 0;
477 } else if (IS_SIMM8(disp)) {
478 return 1;
479 } else {
480 return 2;
481 }
482}
483
484static void emitDisp(CompilationUnit* cUnit, int disp) {
485 if (disp == 0) {
486 return;
487 } else if (IS_SIMM8(disp)) {
488 cUnit->codeBuffer.push_back(disp & 0xFF);
489 } else {
490 cUnit->codeBuffer.push_back(disp & 0xFF);
491 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
492 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
493 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
494 }
495}
496
497static void emitOpReg(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t reg) {
498 if (entry->skeleton.prefix1 != 0) {
499 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
500 if (entry->skeleton.prefix2 != 0) {
501 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
502 }
503 } else {
504 DCHECK_EQ(0, entry->skeleton.prefix2);
505 }
506 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
507 if (entry->skeleton.opcode == 0x0F) {
508 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
509 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
510 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
511 } else {
512 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
513 }
514 } else {
515 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
516 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
517 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700518 if (FPREG(reg)) {
519 reg = reg & FP_REG_MASK;
520 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800521 DCHECK_LT(reg, 8);
522 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
523 cUnit->codeBuffer.push_back(modrm);
524 DCHECK_EQ(0, entry->skeleton.ax_opcode);
525 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
526}
527
528static void emitOpMem(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t base, int disp) {
529 if (entry->skeleton.prefix1 != 0) {
530 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
531 if (entry->skeleton.prefix2 != 0) {
532 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
533 }
534 } else {
535 DCHECK_EQ(0, entry->skeleton.prefix2);
536 }
537 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
538 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
539 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
540 DCHECK_LT(entry->skeleton.modrm_opcode, 8);
541 DCHECK_LT(base, 8);
542 uint8_t modrm = (modrmForDisp(disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
543 cUnit->codeBuffer.push_back(modrm);
544 emitDisp(cUnit, disp);
545 DCHECK_EQ(0, entry->skeleton.ax_opcode);
546 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
547}
548
549static void emitMemReg(CompilationUnit* cUnit, const X86EncodingMap* entry,
550 uint8_t base, int disp, uint8_t reg) {
551 if (entry->skeleton.prefix1 != 0) {
552 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
553 if (entry->skeleton.prefix2 != 0) {
554 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
555 }
556 } else {
557 DCHECK_EQ(0, entry->skeleton.prefix2);
558 }
559 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
560 if (entry->skeleton.opcode == 0x0F) {
561 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
562 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
563 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
564 } else {
565 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
566 }
567 } else {
568 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
569 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
570 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700571 if (FPREG(reg)) {
572 reg = reg & FP_REG_MASK;
573 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800574 DCHECK_LT(reg, 8);
575 DCHECK_LT(base, 8);
576 uint8_t modrm = (modrmForDisp(disp) << 6) | (reg << 3) | base;
577 cUnit->codeBuffer.push_back(modrm);
578 if (base == rSP) {
579 // Special SIB for SP base
580 cUnit->codeBuffer.push_back(0 << 6 | (rSP << 3) | rSP);
581 }
582 emitDisp(cUnit, disp);
583 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
584 DCHECK_EQ(0, entry->skeleton.ax_opcode);
585 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
586}
587
588static void emitRegMem(CompilationUnit* cUnit, const X86EncodingMap* entry,
589 uint8_t reg, uint8_t base, int disp) {
590 // Opcode will flip operands.
591 emitMemReg(cUnit, entry, base, disp, reg);
592}
593
594static void emitRegArray(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t reg,
595 uint8_t base, uint8_t index, int scale, int disp) {
596 if (entry->skeleton.prefix1 != 0) {
597 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
598 if (entry->skeleton.prefix2 != 0) {
599 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
600 }
601 } else {
602 DCHECK_EQ(0, entry->skeleton.prefix2);
603 }
604 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
605 if (entry->skeleton.opcode == 0x0F) {
606 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
607 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
608 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
609 } else {
610 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
611 }
612 } else {
613 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
614 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
615 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700616 if (FPREG(reg)) {
617 reg = reg & FP_REG_MASK;
618 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800619 DCHECK_LT(reg, 8);
620 uint8_t modrm = (modrmForDisp(disp) << 6) | (reg << 3) | rSP;
621 cUnit->codeBuffer.push_back(modrm);
622 DCHECK_LT(scale, 4);
623 DCHECK_LT(index, 8);
624 DCHECK_LT(base, 8);
625 uint8_t sib = (scale << 6) | (index << 3) | base;
626 cUnit->codeBuffer.push_back(sib);
627 emitDisp(cUnit, disp);
628 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
629 DCHECK_EQ(0, entry->skeleton.ax_opcode);
630 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
631}
632
Ian Rogersb41b33b2012-03-20 14:22:54 -0700633static void emitArrayReg(CompilationUnit* cUnit, const X86EncodingMap* entry,
634 uint8_t base, uint8_t index, int scale, int disp, uint8_t reg) {
635 // Opcode will flip operands.
636 emitRegArray(cUnit, entry, reg, base, index, scale, disp);
637}
638
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700639static void emitRegThread(CompilationUnit* cUnit, const X86EncodingMap* entry,
640 uint8_t reg, int disp) {
641 DCHECK_NE(entry->skeleton.prefix1, 0);
642 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
643 if (entry->skeleton.prefix2 != 0) {
644 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
645 }
646 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
647 if (entry->skeleton.opcode == 0x0F) {
648 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
649 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
650 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
651 } else {
652 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
653 }
654 } else {
655 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
656 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
657 }
658 if (FPREG(reg)) {
659 reg = reg & FP_REG_MASK;
660 }
661 DCHECK_LT(reg, 8);
662 uint8_t modrm = (0 << 6) | (reg << 3) | rBP;
663 cUnit->codeBuffer.push_back(modrm);
664 cUnit->codeBuffer.push_back(disp & 0xFF);
665 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
666 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
667 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
668 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
669 DCHECK_EQ(0, entry->skeleton.ax_opcode);
670 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
671}
672
Ian Rogersb5d09b22012-03-06 22:14:17 -0800673static void emitRegReg(CompilationUnit* cUnit, const X86EncodingMap* entry,
674 uint8_t reg1, uint8_t reg2) {
675 if (entry->skeleton.prefix1 != 0) {
676 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
677 if (entry->skeleton.prefix2 != 0) {
678 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
679 }
680 } else {
681 DCHECK_EQ(0, entry->skeleton.prefix2);
682 }
683 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
684 if (entry->skeleton.opcode == 0x0F) {
685 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
686 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
687 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
688 } else {
689 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
690 }
691 } else {
692 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
693 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
694 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700695 if (FPREG(reg1)) {
696 reg1 = reg1 & FP_REG_MASK;
697 }
698 if (FPREG(reg2)) {
699 reg2 = reg2 & FP_REG_MASK;
700 }
701 DCHECK_LT(reg1, 8);
702 DCHECK_LT(reg2, 8);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800703 uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
704 cUnit->codeBuffer.push_back(modrm);
705 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
706 DCHECK_EQ(0, entry->skeleton.ax_opcode);
707 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
708}
709
710static void emitRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
711 uint8_t reg, int imm) {
712 if (entry->skeleton.prefix1 != 0) {
713 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
714 if (entry->skeleton.prefix2 != 0) {
715 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
716 }
717 } else {
718 DCHECK_EQ(0, entry->skeleton.prefix2);
719 }
720 if (reg == rAX && entry->skeleton.ax_opcode != 0) {
721 cUnit->codeBuffer.push_back(entry->skeleton.ax_opcode);
722 } else {
723 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
724 if (entry->skeleton.opcode == 0x0F) {
725 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
726 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
727 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
728 } else {
729 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
730 }
731 } else {
732 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
733 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
734 }
735 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
736 cUnit->codeBuffer.push_back(modrm);
737 }
738 switch (entry->skeleton.immediate_bytes) {
739 case 1:
740 DCHECK(IS_SIMM8(imm));
741 cUnit->codeBuffer.push_back(imm & 0xFF);
742 break;
743 case 2:
744 DCHECK(IS_SIMM16(imm));
745 cUnit->codeBuffer.push_back(imm & 0xFF);
746 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
747 break;
748 case 4:
749 cUnit->codeBuffer.push_back(imm & 0xFF);
750 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
751 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
752 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
753 break;
754 default:
755 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
756 << ") for instruction: " << entry->name;
757 break;
758 }
759}
760
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700761static void emitThreadImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
762 int disp, int imm) {
763 if (entry->skeleton.prefix1 != 0) {
764 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
765 if (entry->skeleton.prefix2 != 0) {
766 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
767 }
768 } else {
769 DCHECK_EQ(0, entry->skeleton.prefix2);
770 }
771 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
772 if (entry->skeleton.opcode == 0x0F) {
773 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
774 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
775 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
776 } else {
777 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
778 }
779 } else {
780 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
781 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
782 }
783 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
784 cUnit->codeBuffer.push_back(modrm);
785 cUnit->codeBuffer.push_back(disp & 0xFF);
786 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
787 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
788 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
789 switch (entry->skeleton.immediate_bytes) {
790 case 1:
791 DCHECK(IS_SIMM8(imm));
792 cUnit->codeBuffer.push_back(imm & 0xFF);
793 break;
794 case 2:
795 DCHECK(IS_SIMM16(imm));
796 cUnit->codeBuffer.push_back(imm & 0xFF);
797 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
798 break;
799 case 4:
800 cUnit->codeBuffer.push_back(imm & 0xFF);
801 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
802 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
803 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
804 break;
805 default:
806 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
807 << ") for instruction: " << entry->name;
808 break;
809 }
810 DCHECK_EQ(entry->skeleton.ax_opcode, 0);
811}
812
813static void emitMovRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
814 uint8_t reg, int imm) {
815 DCHECK_LT(reg, 8);
816 cUnit->codeBuffer.push_back(0xB8 + reg);
817 cUnit->codeBuffer.push_back(imm & 0xFF);
818 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
819 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
820 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
821}
822
Ian Rogersb41b33b2012-03-20 14:22:54 -0700823static void emitShiftRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
Ian Rogers7caad772012-03-30 01:07:54 -0700824 uint8_t reg, int imm) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700825 if (entry->skeleton.prefix1 != 0) {
826 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
827 if (entry->skeleton.prefix2 != 0) {
828 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
829 }
830 } else {
831 DCHECK_EQ(0, entry->skeleton.prefix2);
832 }
833 if (imm != 1) {
834 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
835 } else {
836 // Shorter encoding for 1 bit shift
837 cUnit->codeBuffer.push_back(entry->skeleton.ax_opcode);
838 }
839 if (entry->skeleton.opcode == 0x0F) {
840 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
841 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
842 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
843 } else {
844 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
845 }
846 } else {
847 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
848 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
849 }
850 DCHECK_LT(reg, 8);
Ian Rogers7caad772012-03-30 01:07:54 -0700851 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
Ian Rogersb41b33b2012-03-20 14:22:54 -0700852 cUnit->codeBuffer.push_back(modrm);
853 if (imm != 1) {
854 DCHECK_EQ(entry->skeleton.immediate_bytes, 1);
855 DCHECK(IS_SIMM8(imm));
856 cUnit->codeBuffer.push_back(imm & 0xFF);
857 }
858}
859
Ian Rogers7caad772012-03-30 01:07:54 -0700860static void emitShiftRegCl(CompilationUnit* cUnit, const X86EncodingMap* entry,
861 uint8_t reg, uint8_t cl) {
862 DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
863 if (entry->skeleton.prefix1 != 0) {
864 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
865 if (entry->skeleton.prefix2 != 0) {
866 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
867 }
868 } else {
869 DCHECK_EQ(0, entry->skeleton.prefix2);
870 }
871 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
872 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
873 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
874 DCHECK_LT(reg, 8);
875 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
876 cUnit->codeBuffer.push_back(modrm);
877 DCHECK_EQ(0, entry->skeleton.ax_opcode);
878 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
879}
880
881static void emitRegCond(CompilationUnit* cUnit, const X86EncodingMap* entry,
882 uint8_t reg, uint8_t condition) {
883 if (entry->skeleton.prefix1 != 0) {
884 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
885 if (entry->skeleton.prefix2 != 0) {
886 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
887 }
888 } else {
889 DCHECK_EQ(0, entry->skeleton.prefix2);
890 }
891 DCHECK_EQ(0, entry->skeleton.ax_opcode);
892 DCHECK_EQ(0x0F, entry->skeleton.opcode);
893 cUnit->codeBuffer.push_back(0x0F);
894 DCHECK_EQ(0x90, entry->skeleton.extra_opcode1);
895 cUnit->codeBuffer.push_back(0x90 | condition);
896 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
897 DCHECK_LT(reg, 8);
898 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
899 cUnit->codeBuffer.push_back(modrm);
900 DCHECK_EQ(entry->skeleton.immediate_bytes, 0);
901}
902
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700903static void emitJmp(CompilationUnit* cUnit, const X86EncodingMap* entry, int rel) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700904 if (entry->opcode == kX86Jmp8) {
905 DCHECK(IS_SIMM8(rel));
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700906 cUnit->codeBuffer.push_back(0xEB);
907 cUnit->codeBuffer.push_back(rel & 0xFF);
Ian Rogers7caad772012-03-30 01:07:54 -0700908 } else if (entry->opcode == kX86Jmp32) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700909 cUnit->codeBuffer.push_back(0xE9);
910 cUnit->codeBuffer.push_back(rel & 0xFF);
911 cUnit->codeBuffer.push_back((rel >> 8) & 0xFF);
912 cUnit->codeBuffer.push_back((rel >> 16) & 0xFF);
913 cUnit->codeBuffer.push_back((rel >> 24) & 0xFF);
Ian Rogers7caad772012-03-30 01:07:54 -0700914 } else {
915 DCHECK(entry->opcode == kX86JmpR);
916 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
917 uint8_t reg = static_cast<uint8_t>(rel);
918 DCHECK_LT(reg, 8);
919 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
920 cUnit->codeBuffer.push_back(modrm);
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700921 }
922}
923
924static void emitJcc(CompilationUnit* cUnit, const X86EncodingMap* entry,
925 int rel, uint8_t cc) {
926 DCHECK_LT(cc, 16);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700927 if (entry->opcode == kX86Jcc8) {
928 DCHECK(IS_SIMM8(rel));
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700929 cUnit->codeBuffer.push_back(0x70 | cc);
930 cUnit->codeBuffer.push_back(rel & 0xFF);
931 } else {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700932 DCHECK(entry->opcode == kX86Jcc32);
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700933 cUnit->codeBuffer.push_back(0x0F);
934 cUnit->codeBuffer.push_back(0x80 | cc);
935 cUnit->codeBuffer.push_back(rel & 0xFF);
936 cUnit->codeBuffer.push_back((rel >> 8) & 0xFF);
937 cUnit->codeBuffer.push_back((rel >> 16) & 0xFF);
938 cUnit->codeBuffer.push_back((rel >> 24) & 0xFF);
939 }
940}
941
942static void emitCallMem(CompilationUnit* cUnit, const X86EncodingMap* entry,
943 uint8_t base, int disp) {
944 if (entry->skeleton.prefix1 != 0) {
945 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
946 if (entry->skeleton.prefix2 != 0) {
947 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
948 }
949 } else {
950 DCHECK_EQ(0, entry->skeleton.prefix2);
951 }
952 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
953 if (entry->skeleton.opcode == 0x0F) {
954 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
955 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
956 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
957 } else {
958 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
959 }
960 } else {
961 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
962 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
963 }
964 uint8_t modrm = (modrmForDisp(disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
965 cUnit->codeBuffer.push_back(modrm);
966 if (base == rSP) {
967 // Special SIB for SP base
968 cUnit->codeBuffer.push_back(0 << 6 | (rSP << 3) | rSP);
969 }
970 emitDisp(cUnit, disp);
971 DCHECK_EQ(0, entry->skeleton.ax_opcode);
972 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
973}
974
975static void emitCallThread(CompilationUnit* cUnit, const X86EncodingMap* entry, int disp) {
976 DCHECK_NE(entry->skeleton.prefix1, 0);
977 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
978 if (entry->skeleton.prefix2 != 0) {
979 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
980 }
981 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
982 if (entry->skeleton.opcode == 0x0F) {
983 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
984 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
985 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
986 } else {
987 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
988 }
989 } else {
990 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
991 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
992 }
993 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
994 cUnit->codeBuffer.push_back(modrm);
995 cUnit->codeBuffer.push_back(disp & 0xFF);
996 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
997 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
998 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
999 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1000 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1001}
1002
Ian Rogers7caad772012-03-30 01:07:54 -07001003static void emitPcRel(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t reg,
1004 int base_or_table, uint8_t index, int scale, int table_or_disp) {
1005 int disp;
1006 if (entry->opcode == kX86PcRelLoadRA) {
1007 SwitchTable *tabRec = (SwitchTable*)table_or_disp;
1008 disp = tabRec->offset;
1009 } else {
1010 DCHECK(entry->opcode == kX86PcRelAdr);
1011 FillArrayData *tabRec = (FillArrayData *)base_or_table;
1012 disp = tabRec->offset;
1013 }
1014 if (entry->skeleton.prefix1 != 0) {
1015 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
1016 if (entry->skeleton.prefix2 != 0) {
1017 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
1018 }
1019 } else {
1020 DCHECK_EQ(0, entry->skeleton.prefix2);
1021 }
1022 if (FPREG(reg)) {
1023 reg = reg & FP_REG_MASK;
1024 }
1025 DCHECK_LT(reg, 8);
1026 if (entry->opcode == kX86PcRelLoadRA) {
1027 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
1028 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
1029 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1030 uint8_t modrm = (2 << 6) | (reg << 3) | rSP;
1031 cUnit->codeBuffer.push_back(modrm);
1032 DCHECK_LT(scale, 4);
1033 DCHECK_LT(index, 8);
1034 DCHECK_LT(base_or_table, 8);
1035 uint8_t base = static_cast<uint8_t>(base_or_table);
1036 uint8_t sib = (scale << 6) | (index << 3) | base;
1037 cUnit->codeBuffer.push_back(sib);
1038 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1039 } else {
1040 cUnit->codeBuffer.push_back(entry->skeleton.opcode + reg);
1041 }
1042 cUnit->codeBuffer.push_back(disp & 0xFF);
1043 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
1044 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
1045 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
1046 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
1047 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1048}
1049
1050static void emitMacro(CompilationUnit* cUnit, const X86EncodingMap* entry,
1051 uint8_t reg, int offset) {
1052 DCHECK(entry->opcode == kX86StartOfMethod) << entry->name;
1053 cUnit->codeBuffer.push_back(0xE8); // call +0
1054 cUnit->codeBuffer.push_back(0);
1055 cUnit->codeBuffer.push_back(0);
1056 cUnit->codeBuffer.push_back(0);
1057 cUnit->codeBuffer.push_back(0);
1058
1059 DCHECK_LT(reg, 8);
1060 cUnit->codeBuffer.push_back(0x58 + reg); // pop reg
1061
1062 emitRegImm(cUnit, &EncodingMap[kX86Sub32RI], reg, offset + 5 /* size of call +0 */);
1063}
1064
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001065void emitUnimplemented(CompilationUnit* cUnit, const X86EncodingMap* entry, LIR* lir) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001066 UNIMPLEMENTED(WARNING) << "encoding for: " << entry->name;
Ian Rogers141b0c72012-03-15 18:18:52 -07001067 for (int i = 0; i < oatGetInsnSize(lir); ++i) {
1068 cUnit->codeBuffer.push_back(0xCC); // push breakpoint instruction - int 3
1069 }
1070}
1071
buzbeee88dfbf2012-03-05 11:19:57 -08001072/*
1073 * Assemble the LIR into binary instruction format. Note that we may
1074 * discover that pc-relative displacements may not fit the selected
1075 * instruction. In those cases we will try to substitute a new code
1076 * sequence or request that the trace be shortened and retried.
1077 */
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001078AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08001079 LIR *lir;
1080 AssemblerStatus res = kSuccess; // Assume success
buzbeee88dfbf2012-03-05 11:19:57 -08001081
Ian Rogers141d6222012-04-05 12:23:06 -07001082 const bool kVerbosePcFixup = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001083 for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
1084 if (lir->opcode < 0) {
1085 continue;
buzbeee88dfbf2012-03-05 11:19:57 -08001086 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001087
Ian Rogersb5d09b22012-03-06 22:14:17 -08001088 if (lir->flags.isNop) {
1089 continue;
1090 }
1091
1092 if (lir->flags.pcRelFixup) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001093 switch (lir->opcode) {
Ian Rogersb41b33b2012-03-20 14:22:54 -07001094 case kX86Jcc8: {
1095 LIR *targetLIR = lir->target;
1096 DCHECK(targetLIR != NULL);
1097 int delta = 0;
1098 intptr_t pc;
1099 if (IS_SIMM8(lir->operands[0])) {
1100 pc = lir->offset + 2 /* opcode + rel8 */;
1101 } else {
1102 pc = lir->offset + 6 /* 2 byte opcode + rel32 */;
1103 }
1104 intptr_t target = targetLIR->offset;
1105 delta = target - pc;
1106 if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) {
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001107 if (kVerbosePcFixup) {
1108 LOG(INFO) << "Retry for JCC growth at " << lir->offset
1109 << " delta: " << delta << " old delta: " << lir->operands[0];
1110 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001111 lir->opcode = kX86Jcc32;
1112 oatSetupResourceMasks(lir);
1113 res = kRetryAll;
1114 }
Ian Rogers7caad772012-03-30 01:07:54 -07001115 if (kVerbosePcFixup) {
1116 LOG(INFO) << "Source:";
1117 oatDumpLIRInsn(cUnit, lir, 0);
1118 LOG(INFO) << "Target:";
1119 oatDumpLIRInsn(cUnit, targetLIR, 0);
1120 LOG(INFO) << "Delta " << delta;
1121 }
1122 lir->operands[0] = delta;
1123 break;
1124 }
1125 case kX86Jcc32: {
1126 LIR *targetLIR = lir->target;
1127 DCHECK(targetLIR != NULL);
1128 intptr_t pc = lir->offset + 6 /* 2 byte opcode + rel32 */;
1129 intptr_t target = targetLIR->offset;
1130 int delta = target - pc;
1131 if (kVerbosePcFixup) {
1132 LOG(INFO) << "Source:";
1133 oatDumpLIRInsn(cUnit, lir, 0);
1134 LOG(INFO) << "Target:";
1135 oatDumpLIRInsn(cUnit, targetLIR, 0);
1136 LOG(INFO) << "Delta " << delta;
1137 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001138 lir->operands[0] = delta;
1139 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001140 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001141 case kX86Jmp8: {
1142 LIR *targetLIR = lir->target;
1143 DCHECK(targetLIR != NULL);
1144 int delta = 0;
1145 intptr_t pc;
1146 if (IS_SIMM8(lir->operands[0])) {
1147 pc = lir->offset + 2 /* opcode + rel8 */;
1148 } else {
1149 pc = lir->offset + 5 /* opcode + rel32 */;
1150 }
1151 intptr_t target = targetLIR->offset;
1152 delta = target - pc;
1153 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && lir->operands[0] == 0) {
1154 // Useless branch
1155 lir->flags.isNop = true;
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001156 if (kVerbosePcFixup) {
1157 LOG(INFO) << "Retry for useless branch at " << lir->offset;
1158 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001159 res = kRetryAll;
1160 } else if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) {
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001161 if (kVerbosePcFixup) {
1162 LOG(INFO) << "Retry for JMP growth at " << lir->offset;
1163 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001164 lir->opcode = kX86Jmp32;
1165 oatSetupResourceMasks(lir);
1166 res = kRetryAll;
1167 }
1168 lir->operands[0] = delta;
1169 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001170 }
Ian Rogers7caad772012-03-30 01:07:54 -07001171 case kX86Jmp32: {
1172 LIR *targetLIR = lir->target;
1173 DCHECK(targetLIR != NULL);
1174 intptr_t pc = lir->offset + 5 /* opcode + rel32 */;
1175 intptr_t target = targetLIR->offset;
1176 int delta = target - pc;
1177 lir->operands[0] = delta;
1178 break;
1179 }
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001180 default:
1181 break;
1182 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001183 }
1184
1185 /*
1186 * If one of the pc-relative instructions expanded we'll have
1187 * to make another pass. Don't bother to fully assemble the
1188 * instruction.
1189 */
1190 if (res != kSuccess) {
1191 continue;
1192 }
Ian Rogers7caad772012-03-30 01:07:54 -07001193 CHECK_EQ(static_cast<size_t>(lir->offset), cUnit->codeBuffer.size());
Ian Rogersb5d09b22012-03-06 22:14:17 -08001194 const X86EncodingMap *entry = &EncodingMap[lir->opcode];
Ian Rogers141b0c72012-03-15 18:18:52 -07001195 size_t starting_cbuf_size = cUnit->codeBuffer.size();
Elliott Hughesb25c3f62012-03-26 16:35:06 -07001196 switch (entry->kind) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08001197 case kData: // 4 bytes of data
1198 cUnit->codeBuffer.push_back(lir->operands[0]);
1199 break;
1200 case kNullary: // 1 byte of opcode
1201 DCHECK_EQ(0, entry->skeleton.prefix1);
1202 DCHECK_EQ(0, entry->skeleton.prefix2);
1203 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001204 if (entry->skeleton.extra_opcode1 != 0) {
1205 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
1206 if (entry->skeleton.extra_opcode2 != 0) {
1207 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
1208 }
1209 } else {
1210 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1211 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001212 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
1213 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1214 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1215 break;
1216 case kReg: // lir operands - 0: reg
1217 emitOpReg(cUnit, entry, lir->operands[0]);
1218 break;
1219 case kMem: // lir operands - 0: base, 1: disp
1220 emitOpMem(cUnit, entry, lir->operands[0], lir->operands[1]);
1221 break;
1222 case kMemReg: // lir operands - 0: base, 1: disp, 2: reg
1223 emitMemReg(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1224 break;
Ian Rogersb41b33b2012-03-20 14:22:54 -07001225 case kArrayReg: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
1226 emitArrayReg(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1227 lir->operands[3], lir->operands[4]);
1228 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001229 case kRegMem: // lir operands - 0: reg, 1: base, 2: disp
1230 emitRegMem(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1231 break;
1232 case kRegArray: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp
1233 emitRegArray(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1234 lir->operands[3], lir->operands[4]);
1235 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001236 case kRegThread: // lir operands - 0: reg, 1: disp
1237 emitRegThread(cUnit, entry, lir->operands[0], lir->operands[1]);
1238 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001239 case kRegReg: // lir operands - 0: reg1, 1: reg2
1240 emitRegReg(cUnit, entry, lir->operands[0], lir->operands[1]);
1241 break;
1242 case kRegImm: // lir operands - 0: reg, 1: immediate
1243 emitRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1244 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001245 case kThreadImm: // lir operands - 0: disp, 1: immediate
1246 emitThreadImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1247 break;
1248 case kMovRegImm: // lir operands - 0: reg, 1: immediate
1249 emitMovRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1250 break;
Ian Rogersb41b33b2012-03-20 14:22:54 -07001251 case kShiftRegImm: // lir operands - 0: reg, 1: immediate
1252 emitShiftRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1253 break;
Ian Rogers7caad772012-03-30 01:07:54 -07001254 case kShiftRegCl: // lir operands - 0: reg, 1: cl
1255 emitShiftRegCl(cUnit, entry, lir->operands[0], lir->operands[1]);
1256 break;
1257 case kRegCond: // lir operands - 0: reg, 1: condition
1258 emitRegCond(cUnit, entry, lir->operands[0], lir->operands[1]);
1259 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001260 case kJmp: // lir operands - 0: rel
1261 emitJmp(cUnit, entry, lir->operands[0]);
1262 break;
1263 case kJcc: // lir operands - 0: rel, 1: CC, target assigned
1264 emitJcc(cUnit, entry, lir->operands[0], lir->operands[1]);
1265 break;
1266 case kCall:
Elliott Hughesb25c3f62012-03-26 16:35:06 -07001267 switch (entry->opcode) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001268 case kX86CallM: // lir operands - 0: base, 1: disp
1269 emitCallMem(cUnit, entry, lir->operands[0], lir->operands[1]);
1270 break;
1271 case kX86CallT: // lir operands - 0: disp
1272 emitCallThread(cUnit, entry, lir->operands[0]);
1273 break;
1274 default:
1275 emitUnimplemented(cUnit, entry, lir);
1276 break;
1277 }
1278 break;
Ian Rogers7caad772012-03-30 01:07:54 -07001279 case kPcRel: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: table
1280 emitPcRel(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1281 lir->operands[3], lir->operands[4]);
1282 break;
1283 case kMacro:
1284 emitMacro(cUnit, entry, lir->operands[0], lir->offset);
1285 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001286 default:
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001287 emitUnimplemented(cUnit, entry, lir);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001288 break;
1289 }
Ian Rogers7caad772012-03-30 01:07:54 -07001290 CHECK_EQ(static_cast<size_t>(oatGetInsnSize(lir)),
1291 cUnit->codeBuffer.size() - starting_cbuf_size)
1292 << "Instruction size mismatch for entry: " << EncodingMap[lir->opcode].name;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001293 }
1294 return res;
buzbeee88dfbf2012-03-05 11:19:57 -08001295}
1296
buzbeee88dfbf2012-03-05 11:19:57 -08001297/*
1298 * Target-dependent offset assignment.
1299 * independent.
1300 */
1301int oatAssignInsnOffsets(CompilationUnit* cUnit)
1302{
1303 LIR* x86LIR;
1304 int offset = 0;
1305
1306 for (x86LIR = (LIR *) cUnit->firstLIRInsn;
1307 x86LIR;
1308 x86LIR = NEXT_LIR(x86LIR)) {
1309 x86LIR->offset = offset;
1310 if (x86LIR->opcode >= 0) {
1311 if (!x86LIR->flags.isNop) {
1312 offset += x86LIR->flags.size;
1313 }
1314 } else if (x86LIR->opcode == kPseudoPseudoAlign4) {
1315 if (offset & 0x2) {
1316 offset += 2;
1317 x86LIR->operands[0] = 1;
1318 } else {
1319 x86LIR->operands[0] = 0;
1320 }
1321 }
1322 /* Pseudo opcodes don't consume space */
1323 }
1324
1325 return offset;
1326}
1327
1328} // namespace art