blob: d9cdabf621ab516b54fd04bb49de1514c3d37c15 [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
Elliott Hughes225ae522012-04-16 20:21:45 -0700133 { kX86Imul16RRI, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RRI", "!0r,!1r,!2d" },
134 { kX86Imul16RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RMI", "!0r,[!1r+!2d],!3d" },
135 { kX86Imul16RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RAI", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
Ian Rogersb5d09b22012-03-06 22:14:17 -0800136
Elliott Hughes225ae522012-04-16 20:21:45 -0700137 { kX86Imul32RRI, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RRI", "!0r,!1r,!2d" },
138 { kX86Imul32RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RMI", "!0r,[!1r+!2d],!3d" },
139 { kX86Imul32RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RAI", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
140 { kX86Imul32RRI8, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RRI8", "!0r,!1r,!2d" },
141 { kX86Imul32RMI8, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RMI8", "!0r,[!1r+!2d],!3d" },
142 { kX86Imul32RAI8, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RAI8", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
Ian Rogersb5d09b22012-03-06 22:14:17 -0800143
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 Rogers5450e0e2012-04-16 16:05:57 -0700272 { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 6, 0, 1 }, "PsllqRI", "!0r, !1d" },
Ian Rogersb41b33b2012-03-20 14:22:54 -0700273
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
Elliott Hughes225ae522012-04-16 20:21:45 -0700710static void emitRegRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
711 uint8_t reg1, uint8_t reg2, int32_t 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 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
721 if (entry->skeleton.opcode == 0x0F) {
722 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
723 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
724 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
725 } else {
726 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
727 }
728 } else {
729 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
730 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
731 }
732 if (FPREG(reg1)) {
733 reg1 = reg1 & FP_REG_MASK;
734 }
735 if (FPREG(reg2)) {
736 reg2 = reg2 & FP_REG_MASK;
737 }
738 DCHECK_LT(reg1, 8);
739 DCHECK_LT(reg2, 8);
740 uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
741 cUnit->codeBuffer.push_back(modrm);
742 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
743 DCHECK_EQ(0, entry->skeleton.ax_opcode);
744 switch (entry->skeleton.immediate_bytes) {
745 case 1:
746 DCHECK(IS_SIMM8(imm));
747 cUnit->codeBuffer.push_back(imm & 0xFF);
748 break;
749 case 2:
750 DCHECK(IS_SIMM16(imm));
751 cUnit->codeBuffer.push_back(imm & 0xFF);
752 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
753 break;
754 case 4:
755 cUnit->codeBuffer.push_back(imm & 0xFF);
756 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
757 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
758 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
759 break;
760 default:
761 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
762 << ") for instruction: " << entry->name;
763 break;
764 }
765}
766
Ian Rogersb5d09b22012-03-06 22:14:17 -0800767static void emitRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
768 uint8_t reg, int imm) {
769 if (entry->skeleton.prefix1 != 0) {
770 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
771 if (entry->skeleton.prefix2 != 0) {
772 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
773 }
774 } else {
775 DCHECK_EQ(0, entry->skeleton.prefix2);
776 }
777 if (reg == rAX && entry->skeleton.ax_opcode != 0) {
778 cUnit->codeBuffer.push_back(entry->skeleton.ax_opcode);
779 } else {
780 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
781 if (entry->skeleton.opcode == 0x0F) {
782 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
783 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
784 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
785 } else {
786 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
787 }
788 } else {
789 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
790 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
791 }
792 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
793 cUnit->codeBuffer.push_back(modrm);
794 }
795 switch (entry->skeleton.immediate_bytes) {
796 case 1:
797 DCHECK(IS_SIMM8(imm));
798 cUnit->codeBuffer.push_back(imm & 0xFF);
799 break;
800 case 2:
801 DCHECK(IS_SIMM16(imm));
802 cUnit->codeBuffer.push_back(imm & 0xFF);
803 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
804 break;
805 case 4:
806 cUnit->codeBuffer.push_back(imm & 0xFF);
807 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
808 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
809 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
810 break;
811 default:
812 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
813 << ") for instruction: " << entry->name;
814 break;
815 }
816}
817
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700818static void emitThreadImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
819 int disp, int imm) {
820 if (entry->skeleton.prefix1 != 0) {
821 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
822 if (entry->skeleton.prefix2 != 0) {
823 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
824 }
825 } else {
826 DCHECK_EQ(0, entry->skeleton.prefix2);
827 }
828 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
829 if (entry->skeleton.opcode == 0x0F) {
830 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
831 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
832 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
833 } else {
834 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
835 }
836 } else {
837 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
838 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
839 }
840 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
841 cUnit->codeBuffer.push_back(modrm);
842 cUnit->codeBuffer.push_back(disp & 0xFF);
843 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
844 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
845 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
846 switch (entry->skeleton.immediate_bytes) {
847 case 1:
848 DCHECK(IS_SIMM8(imm));
849 cUnit->codeBuffer.push_back(imm & 0xFF);
850 break;
851 case 2:
852 DCHECK(IS_SIMM16(imm));
853 cUnit->codeBuffer.push_back(imm & 0xFF);
854 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
855 break;
856 case 4:
857 cUnit->codeBuffer.push_back(imm & 0xFF);
858 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
859 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
860 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
861 break;
862 default:
863 LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
864 << ") for instruction: " << entry->name;
865 break;
866 }
867 DCHECK_EQ(entry->skeleton.ax_opcode, 0);
868}
869
870static void emitMovRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
871 uint8_t reg, int imm) {
872 DCHECK_LT(reg, 8);
873 cUnit->codeBuffer.push_back(0xB8 + reg);
874 cUnit->codeBuffer.push_back(imm & 0xFF);
875 cUnit->codeBuffer.push_back((imm >> 8) & 0xFF);
876 cUnit->codeBuffer.push_back((imm >> 16) & 0xFF);
877 cUnit->codeBuffer.push_back((imm >> 24) & 0xFF);
878}
879
Ian Rogersb41b33b2012-03-20 14:22:54 -0700880static void emitShiftRegImm(CompilationUnit* cUnit, const X86EncodingMap* entry,
Ian Rogers7caad772012-03-30 01:07:54 -0700881 uint8_t reg, int imm) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700882 if (entry->skeleton.prefix1 != 0) {
883 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
884 if (entry->skeleton.prefix2 != 0) {
885 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
886 }
887 } else {
888 DCHECK_EQ(0, entry->skeleton.prefix2);
889 }
890 if (imm != 1) {
891 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
892 } else {
893 // Shorter encoding for 1 bit shift
894 cUnit->codeBuffer.push_back(entry->skeleton.ax_opcode);
895 }
896 if (entry->skeleton.opcode == 0x0F) {
897 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
898 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
899 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
900 } else {
901 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
902 }
903 } else {
904 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
905 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
906 }
907 DCHECK_LT(reg, 8);
Ian Rogers7caad772012-03-30 01:07:54 -0700908 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
Ian Rogersb41b33b2012-03-20 14:22:54 -0700909 cUnit->codeBuffer.push_back(modrm);
910 if (imm != 1) {
911 DCHECK_EQ(entry->skeleton.immediate_bytes, 1);
912 DCHECK(IS_SIMM8(imm));
913 cUnit->codeBuffer.push_back(imm & 0xFF);
914 }
915}
916
Ian Rogers7caad772012-03-30 01:07:54 -0700917static void emitShiftRegCl(CompilationUnit* cUnit, const X86EncodingMap* entry,
918 uint8_t reg, uint8_t cl) {
919 DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
920 if (entry->skeleton.prefix1 != 0) {
921 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
922 if (entry->skeleton.prefix2 != 0) {
923 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
924 }
925 } else {
926 DCHECK_EQ(0, entry->skeleton.prefix2);
927 }
928 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
929 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
930 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
931 DCHECK_LT(reg, 8);
932 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
933 cUnit->codeBuffer.push_back(modrm);
934 DCHECK_EQ(0, entry->skeleton.ax_opcode);
935 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
936}
937
938static void emitRegCond(CompilationUnit* cUnit, const X86EncodingMap* entry,
939 uint8_t reg, uint8_t condition) {
940 if (entry->skeleton.prefix1 != 0) {
941 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
942 if (entry->skeleton.prefix2 != 0) {
943 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
944 }
945 } else {
946 DCHECK_EQ(0, entry->skeleton.prefix2);
947 }
948 DCHECK_EQ(0, entry->skeleton.ax_opcode);
949 DCHECK_EQ(0x0F, entry->skeleton.opcode);
950 cUnit->codeBuffer.push_back(0x0F);
951 DCHECK_EQ(0x90, entry->skeleton.extra_opcode1);
952 cUnit->codeBuffer.push_back(0x90 | condition);
953 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
954 DCHECK_LT(reg, 8);
955 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
956 cUnit->codeBuffer.push_back(modrm);
957 DCHECK_EQ(entry->skeleton.immediate_bytes, 0);
958}
959
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700960static void emitJmp(CompilationUnit* cUnit, const X86EncodingMap* entry, int rel) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700961 if (entry->opcode == kX86Jmp8) {
962 DCHECK(IS_SIMM8(rel));
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700963 cUnit->codeBuffer.push_back(0xEB);
964 cUnit->codeBuffer.push_back(rel & 0xFF);
Ian Rogers7caad772012-03-30 01:07:54 -0700965 } else if (entry->opcode == kX86Jmp32) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700966 cUnit->codeBuffer.push_back(0xE9);
967 cUnit->codeBuffer.push_back(rel & 0xFF);
968 cUnit->codeBuffer.push_back((rel >> 8) & 0xFF);
969 cUnit->codeBuffer.push_back((rel >> 16) & 0xFF);
970 cUnit->codeBuffer.push_back((rel >> 24) & 0xFF);
Ian Rogers7caad772012-03-30 01:07:54 -0700971 } else {
972 DCHECK(entry->opcode == kX86JmpR);
973 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
974 uint8_t reg = static_cast<uint8_t>(rel);
975 DCHECK_LT(reg, 8);
976 uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
977 cUnit->codeBuffer.push_back(modrm);
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700978 }
979}
980
981static void emitJcc(CompilationUnit* cUnit, const X86EncodingMap* entry,
982 int rel, uint8_t cc) {
983 DCHECK_LT(cc, 16);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700984 if (entry->opcode == kX86Jcc8) {
985 DCHECK(IS_SIMM8(rel));
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700986 cUnit->codeBuffer.push_back(0x70 | cc);
987 cUnit->codeBuffer.push_back(rel & 0xFF);
988 } else {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700989 DCHECK(entry->opcode == kX86Jcc32);
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700990 cUnit->codeBuffer.push_back(0x0F);
991 cUnit->codeBuffer.push_back(0x80 | cc);
992 cUnit->codeBuffer.push_back(rel & 0xFF);
993 cUnit->codeBuffer.push_back((rel >> 8) & 0xFF);
994 cUnit->codeBuffer.push_back((rel >> 16) & 0xFF);
995 cUnit->codeBuffer.push_back((rel >> 24) & 0xFF);
996 }
997}
998
999static void emitCallMem(CompilationUnit* cUnit, const X86EncodingMap* entry,
1000 uint8_t base, int disp) {
1001 if (entry->skeleton.prefix1 != 0) {
1002 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
1003 if (entry->skeleton.prefix2 != 0) {
1004 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
1005 }
1006 } else {
1007 DCHECK_EQ(0, entry->skeleton.prefix2);
1008 }
1009 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
1010 if (entry->skeleton.opcode == 0x0F) {
1011 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
1012 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
1013 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
1014 } else {
1015 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1016 }
1017 } else {
1018 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
1019 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1020 }
1021 uint8_t modrm = (modrmForDisp(disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
1022 cUnit->codeBuffer.push_back(modrm);
1023 if (base == rSP) {
1024 // Special SIB for SP base
1025 cUnit->codeBuffer.push_back(0 << 6 | (rSP << 3) | rSP);
1026 }
1027 emitDisp(cUnit, disp);
1028 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1029 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1030}
1031
1032static void emitCallThread(CompilationUnit* cUnit, const X86EncodingMap* entry, int disp) {
1033 DCHECK_NE(entry->skeleton.prefix1, 0);
1034 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
1035 if (entry->skeleton.prefix2 != 0) {
1036 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
1037 }
1038 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
1039 if (entry->skeleton.opcode == 0x0F) {
1040 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
1041 if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode2 == 0x3A) {
1042 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
1043 } else {
1044 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1045 }
1046 } else {
1047 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
1048 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1049 }
1050 uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
1051 cUnit->codeBuffer.push_back(modrm);
1052 cUnit->codeBuffer.push_back(disp & 0xFF);
1053 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
1054 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
1055 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
1056 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1057 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1058}
1059
Ian Rogers7caad772012-03-30 01:07:54 -07001060static void emitPcRel(CompilationUnit* cUnit, const X86EncodingMap* entry, uint8_t reg,
1061 int base_or_table, uint8_t index, int scale, int table_or_disp) {
1062 int disp;
1063 if (entry->opcode == kX86PcRelLoadRA) {
1064 SwitchTable *tabRec = (SwitchTable*)table_or_disp;
1065 disp = tabRec->offset;
1066 } else {
1067 DCHECK(entry->opcode == kX86PcRelAdr);
1068 FillArrayData *tabRec = (FillArrayData *)base_or_table;
1069 disp = tabRec->offset;
1070 }
1071 if (entry->skeleton.prefix1 != 0) {
1072 cUnit->codeBuffer.push_back(entry->skeleton.prefix1);
1073 if (entry->skeleton.prefix2 != 0) {
1074 cUnit->codeBuffer.push_back(entry->skeleton.prefix2);
1075 }
1076 } else {
1077 DCHECK_EQ(0, entry->skeleton.prefix2);
1078 }
1079 if (FPREG(reg)) {
1080 reg = reg & FP_REG_MASK;
1081 }
1082 DCHECK_LT(reg, 8);
1083 if (entry->opcode == kX86PcRelLoadRA) {
1084 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
1085 DCHECK_EQ(0, entry->skeleton.extra_opcode1);
1086 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1087 uint8_t modrm = (2 << 6) | (reg << 3) | rSP;
1088 cUnit->codeBuffer.push_back(modrm);
1089 DCHECK_LT(scale, 4);
1090 DCHECK_LT(index, 8);
1091 DCHECK_LT(base_or_table, 8);
1092 uint8_t base = static_cast<uint8_t>(base_or_table);
1093 uint8_t sib = (scale << 6) | (index << 3) | base;
1094 cUnit->codeBuffer.push_back(sib);
1095 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1096 } else {
1097 cUnit->codeBuffer.push_back(entry->skeleton.opcode + reg);
1098 }
1099 cUnit->codeBuffer.push_back(disp & 0xFF);
1100 cUnit->codeBuffer.push_back((disp >> 8) & 0xFF);
1101 cUnit->codeBuffer.push_back((disp >> 16) & 0xFF);
1102 cUnit->codeBuffer.push_back((disp >> 24) & 0xFF);
1103 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
1104 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1105}
1106
1107static void emitMacro(CompilationUnit* cUnit, const X86EncodingMap* entry,
1108 uint8_t reg, int offset) {
1109 DCHECK(entry->opcode == kX86StartOfMethod) << entry->name;
1110 cUnit->codeBuffer.push_back(0xE8); // call +0
1111 cUnit->codeBuffer.push_back(0);
1112 cUnit->codeBuffer.push_back(0);
1113 cUnit->codeBuffer.push_back(0);
1114 cUnit->codeBuffer.push_back(0);
1115
1116 DCHECK_LT(reg, 8);
1117 cUnit->codeBuffer.push_back(0x58 + reg); // pop reg
1118
1119 emitRegImm(cUnit, &EncodingMap[kX86Sub32RI], reg, offset + 5 /* size of call +0 */);
1120}
1121
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001122void emitUnimplemented(CompilationUnit* cUnit, const X86EncodingMap* entry, LIR* lir) {
Elliott Hughes225ae522012-04-16 20:21:45 -07001123 UNIMPLEMENTED(WARNING) << "encoding kind for " << entry->name << " " << buildInsnString(entry->fmt, lir, 0);
Ian Rogers141b0c72012-03-15 18:18:52 -07001124 for (int i = 0; i < oatGetInsnSize(lir); ++i) {
1125 cUnit->codeBuffer.push_back(0xCC); // push breakpoint instruction - int 3
1126 }
1127}
1128
buzbeee88dfbf2012-03-05 11:19:57 -08001129/*
1130 * Assemble the LIR into binary instruction format. Note that we may
1131 * discover that pc-relative displacements may not fit the selected
1132 * instruction. In those cases we will try to substitute a new code
1133 * sequence or request that the trace be shortened and retried.
1134 */
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001135AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08001136 LIR *lir;
1137 AssemblerStatus res = kSuccess; // Assume success
buzbeee88dfbf2012-03-05 11:19:57 -08001138
Ian Rogers141d6222012-04-05 12:23:06 -07001139 const bool kVerbosePcFixup = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001140 for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
1141 if (lir->opcode < 0) {
1142 continue;
buzbeee88dfbf2012-03-05 11:19:57 -08001143 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001144
Ian Rogersb5d09b22012-03-06 22:14:17 -08001145 if (lir->flags.isNop) {
1146 continue;
1147 }
1148
1149 if (lir->flags.pcRelFixup) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001150 switch (lir->opcode) {
Ian Rogersb41b33b2012-03-20 14:22:54 -07001151 case kX86Jcc8: {
1152 LIR *targetLIR = lir->target;
1153 DCHECK(targetLIR != NULL);
1154 int delta = 0;
1155 intptr_t pc;
1156 if (IS_SIMM8(lir->operands[0])) {
1157 pc = lir->offset + 2 /* opcode + rel8 */;
1158 } else {
1159 pc = lir->offset + 6 /* 2 byte opcode + rel32 */;
1160 }
1161 intptr_t target = targetLIR->offset;
1162 delta = target - pc;
1163 if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) {
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001164 if (kVerbosePcFixup) {
1165 LOG(INFO) << "Retry for JCC growth at " << lir->offset
1166 << " delta: " << delta << " old delta: " << lir->operands[0];
1167 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001168 lir->opcode = kX86Jcc32;
1169 oatSetupResourceMasks(lir);
1170 res = kRetryAll;
1171 }
Ian Rogers7caad772012-03-30 01:07:54 -07001172 if (kVerbosePcFixup) {
1173 LOG(INFO) << "Source:";
1174 oatDumpLIRInsn(cUnit, lir, 0);
1175 LOG(INFO) << "Target:";
1176 oatDumpLIRInsn(cUnit, targetLIR, 0);
1177 LOG(INFO) << "Delta " << delta;
1178 }
1179 lir->operands[0] = delta;
1180 break;
1181 }
1182 case kX86Jcc32: {
1183 LIR *targetLIR = lir->target;
1184 DCHECK(targetLIR != NULL);
1185 intptr_t pc = lir->offset + 6 /* 2 byte opcode + rel32 */;
1186 intptr_t target = targetLIR->offset;
1187 int delta = target - pc;
1188 if (kVerbosePcFixup) {
1189 LOG(INFO) << "Source:";
1190 oatDumpLIRInsn(cUnit, lir, 0);
1191 LOG(INFO) << "Target:";
1192 oatDumpLIRInsn(cUnit, targetLIR, 0);
1193 LOG(INFO) << "Delta " << delta;
1194 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001195 lir->operands[0] = delta;
1196 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001197 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001198 case kX86Jmp8: {
1199 LIR *targetLIR = lir->target;
1200 DCHECK(targetLIR != NULL);
1201 int delta = 0;
1202 intptr_t pc;
1203 if (IS_SIMM8(lir->operands[0])) {
1204 pc = lir->offset + 2 /* opcode + rel8 */;
1205 } else {
1206 pc = lir->offset + 5 /* opcode + rel32 */;
1207 }
1208 intptr_t target = targetLIR->offset;
1209 delta = target - pc;
1210 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && lir->operands[0] == 0) {
1211 // Useless branch
1212 lir->flags.isNop = true;
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001213 if (kVerbosePcFixup) {
1214 LOG(INFO) << "Retry for useless branch at " << lir->offset;
1215 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001216 res = kRetryAll;
1217 } else if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) {
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001218 if (kVerbosePcFixup) {
1219 LOG(INFO) << "Retry for JMP growth at " << lir->offset;
1220 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001221 lir->opcode = kX86Jmp32;
1222 oatSetupResourceMasks(lir);
1223 res = kRetryAll;
1224 }
1225 lir->operands[0] = delta;
1226 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001227 }
Ian Rogers7caad772012-03-30 01:07:54 -07001228 case kX86Jmp32: {
1229 LIR *targetLIR = lir->target;
1230 DCHECK(targetLIR != NULL);
1231 intptr_t pc = lir->offset + 5 /* opcode + rel32 */;
1232 intptr_t target = targetLIR->offset;
1233 int delta = target - pc;
1234 lir->operands[0] = delta;
1235 break;
1236 }
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001237 default:
1238 break;
1239 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001240 }
1241
1242 /*
1243 * If one of the pc-relative instructions expanded we'll have
1244 * to make another pass. Don't bother to fully assemble the
1245 * instruction.
1246 */
1247 if (res != kSuccess) {
1248 continue;
1249 }
Ian Rogers7caad772012-03-30 01:07:54 -07001250 CHECK_EQ(static_cast<size_t>(lir->offset), cUnit->codeBuffer.size());
Ian Rogersb5d09b22012-03-06 22:14:17 -08001251 const X86EncodingMap *entry = &EncodingMap[lir->opcode];
Ian Rogers141b0c72012-03-15 18:18:52 -07001252 size_t starting_cbuf_size = cUnit->codeBuffer.size();
Elliott Hughesb25c3f62012-03-26 16:35:06 -07001253 switch (entry->kind) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08001254 case kData: // 4 bytes of data
1255 cUnit->codeBuffer.push_back(lir->operands[0]);
1256 break;
1257 case kNullary: // 1 byte of opcode
1258 DCHECK_EQ(0, entry->skeleton.prefix1);
1259 DCHECK_EQ(0, entry->skeleton.prefix2);
1260 cUnit->codeBuffer.push_back(entry->skeleton.opcode);
Ian Rogersc6f3bb82012-03-21 20:40:33 -07001261 if (entry->skeleton.extra_opcode1 != 0) {
1262 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode1);
1263 if (entry->skeleton.extra_opcode2 != 0) {
1264 cUnit->codeBuffer.push_back(entry->skeleton.extra_opcode2);
1265 }
1266 } else {
1267 DCHECK_EQ(0, entry->skeleton.extra_opcode2);
1268 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001269 DCHECK_EQ(0, entry->skeleton.modrm_opcode);
1270 DCHECK_EQ(0, entry->skeleton.ax_opcode);
1271 DCHECK_EQ(0, entry->skeleton.immediate_bytes);
1272 break;
1273 case kReg: // lir operands - 0: reg
1274 emitOpReg(cUnit, entry, lir->operands[0]);
1275 break;
1276 case kMem: // lir operands - 0: base, 1: disp
1277 emitOpMem(cUnit, entry, lir->operands[0], lir->operands[1]);
1278 break;
1279 case kMemReg: // lir operands - 0: base, 1: disp, 2: reg
1280 emitMemReg(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1281 break;
Ian Rogersb41b33b2012-03-20 14:22:54 -07001282 case kArrayReg: // lir operands - 0: base, 1: index, 2: scale, 3: disp, 4: reg
1283 emitArrayReg(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1284 lir->operands[3], lir->operands[4]);
1285 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001286 case kRegMem: // lir operands - 0: reg, 1: base, 2: disp
1287 emitRegMem(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1288 break;
1289 case kRegArray: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: disp
1290 emitRegArray(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1291 lir->operands[3], lir->operands[4]);
1292 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001293 case kRegThread: // lir operands - 0: reg, 1: disp
1294 emitRegThread(cUnit, entry, lir->operands[0], lir->operands[1]);
1295 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001296 case kRegReg: // lir operands - 0: reg1, 1: reg2
1297 emitRegReg(cUnit, entry, lir->operands[0], lir->operands[1]);
1298 break;
Elliott Hughes225ae522012-04-16 20:21:45 -07001299 case kRegRegImm:
1300 emitRegRegImm(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2]);
1301 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001302 case kRegImm: // lir operands - 0: reg, 1: immediate
1303 emitRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1304 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001305 case kThreadImm: // lir operands - 0: disp, 1: immediate
1306 emitThreadImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1307 break;
1308 case kMovRegImm: // lir operands - 0: reg, 1: immediate
1309 emitMovRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1310 break;
Ian Rogersb41b33b2012-03-20 14:22:54 -07001311 case kShiftRegImm: // lir operands - 0: reg, 1: immediate
1312 emitShiftRegImm(cUnit, entry, lir->operands[0], lir->operands[1]);
1313 break;
Ian Rogers7caad772012-03-30 01:07:54 -07001314 case kShiftRegCl: // lir operands - 0: reg, 1: cl
1315 emitShiftRegCl(cUnit, entry, lir->operands[0], lir->operands[1]);
1316 break;
1317 case kRegCond: // lir operands - 0: reg, 1: condition
1318 emitRegCond(cUnit, entry, lir->operands[0], lir->operands[1]);
1319 break;
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001320 case kJmp: // lir operands - 0: rel
1321 emitJmp(cUnit, entry, lir->operands[0]);
1322 break;
1323 case kJcc: // lir operands - 0: rel, 1: CC, target assigned
1324 emitJcc(cUnit, entry, lir->operands[0], lir->operands[1]);
1325 break;
1326 case kCall:
Elliott Hughesb25c3f62012-03-26 16:35:06 -07001327 switch (entry->opcode) {
Ian Rogersb3ab25b2012-03-19 01:12:01 -07001328 case kX86CallM: // lir operands - 0: base, 1: disp
1329 emitCallMem(cUnit, entry, lir->operands[0], lir->operands[1]);
1330 break;
1331 case kX86CallT: // lir operands - 0: disp
1332 emitCallThread(cUnit, entry, lir->operands[0]);
1333 break;
1334 default:
1335 emitUnimplemented(cUnit, entry, lir);
1336 break;
1337 }
1338 break;
Ian Rogers7caad772012-03-30 01:07:54 -07001339 case kPcRel: // lir operands - 0: reg, 1: base, 2: index, 3: scale, 4: table
1340 emitPcRel(cUnit, entry, lir->operands[0], lir->operands[1], lir->operands[2],
1341 lir->operands[3], lir->operands[4]);
1342 break;
1343 case kMacro:
1344 emitMacro(cUnit, entry, lir->operands[0], lir->offset);
1345 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001346 default:
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001347 emitUnimplemented(cUnit, entry, lir);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001348 break;
1349 }
Ian Rogers7caad772012-03-30 01:07:54 -07001350 CHECK_EQ(static_cast<size_t>(oatGetInsnSize(lir)),
1351 cUnit->codeBuffer.size() - starting_cbuf_size)
1352 << "Instruction size mismatch for entry: " << EncodingMap[lir->opcode].name;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001353 }
1354 return res;
buzbeee88dfbf2012-03-05 11:19:57 -08001355}
1356
buzbeee88dfbf2012-03-05 11:19:57 -08001357/*
1358 * Target-dependent offset assignment.
1359 * independent.
1360 */
1361int oatAssignInsnOffsets(CompilationUnit* cUnit)
1362{
1363 LIR* x86LIR;
1364 int offset = 0;
1365
1366 for (x86LIR = (LIR *) cUnit->firstLIRInsn;
1367 x86LIR;
1368 x86LIR = NEXT_LIR(x86LIR)) {
1369 x86LIR->offset = offset;
1370 if (x86LIR->opcode >= 0) {
1371 if (!x86LIR->flags.isNop) {
1372 offset += x86LIR->flags.size;
1373 }
1374 } else if (x86LIR->opcode == kPseudoPseudoAlign4) {
1375 if (offset & 0x2) {
1376 offset += 2;
1377 x86LIR->operands[0] = 1;
1378 } else {
1379 x86LIR->operands[0] = 0;
1380 }
1381 }
1382 /* Pseudo opcodes don't consume space */
1383 }
1384
1385 return offset;
1386}
1387
1388} // namespace art