comparison gen/asm-x86-64.h @ 944:eb310635d80e

Fixed accessing function symbols from inline asm. Ran x86(-64) asm processors through a code formatter.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sun, 08 Feb 2009 05:14:24 +0100
parents acd745fbdb66
children f33413a955fa
comparison
equal deleted inserted replaced
943:95d09451cb59 944:eb310635d80e
1 // Taken from GDC source tree. Original by David Friedman. 1 // Taken from GDC source tree. Original by David Friedman.
2 // Released under the Artistic License found in dmd/artistic.txt 2 // Released under the Artistic License found in dmd/artistic.txt
3 3
4 #include "id.h" 4 #include "id.h"
5 5
6 namespace AsmParserx8664 { 6 namespace AsmParserx8664
7 7 {
8 typedef enum { 8
9 Reg_Invalid = -1, 9 typedef enum
10 Reg_EAX = 0, 10 {
11 Reg_EBX, 11 Reg_Invalid = -1,
12 Reg_ECX, 12 Reg_EAX = 0,
13 Reg_EDX, 13 Reg_EBX,
14 Reg_ESI, 14 Reg_ECX,
15 Reg_EDI, 15 Reg_EDX,
16 Reg_EBP, 16 Reg_ESI,
17 Reg_ESP, 17 Reg_EDI,
18 Reg_ST, 18 Reg_EBP,
19 Reg_ST1, Reg_ST2, Reg_ST3, Reg_ST4, Reg_ST5, Reg_ST6, Reg_ST7, 19 Reg_ESP,
20 Reg_MM0, Reg_MM1, Reg_MM2, Reg_MM3, Reg_MM4, Reg_MM5, Reg_MM6, Reg_MM7, 20 Reg_ST,
21 Reg_XMM0, Reg_XMM1, Reg_XMM2, Reg_XMM3, Reg_XMM4, Reg_XMM5, Reg_XMM6, Reg_XMM7, 21 Reg_ST1, Reg_ST2, Reg_ST3, Reg_ST4, Reg_ST5, Reg_ST6, Reg_ST7,
22 22 Reg_MM0, Reg_MM1, Reg_MM2, Reg_MM3, Reg_MM4, Reg_MM5, Reg_MM6, Reg_MM7,
23 Reg_RAX, Reg_RBX, Reg_RCX, Reg_RDX, Reg_RSI, Reg_RDI, Reg_RBP, Reg_RSP, 23 Reg_XMM0, Reg_XMM1, Reg_XMM2, Reg_XMM3, Reg_XMM4, Reg_XMM5, Reg_XMM6, Reg_XMM7,
24 Reg_R8, Reg_R9, Reg_R10, Reg_R11, Reg_R12, Reg_R13, Reg_R14, Reg_R15, 24
25 Reg_R8B, Reg_R9B, Reg_R10B, Reg_R11B, Reg_R12B, Reg_R13B, Reg_R14B, Reg_R15B, 25 Reg_RAX, Reg_RBX, Reg_RCX, Reg_RDX, Reg_RSI, Reg_RDI, Reg_RBP, Reg_RSP,
26 Reg_R8W, Reg_R9W, Reg_R10W, Reg_R11W, Reg_R12W, Reg_R13W, Reg_R14W, Reg_R15W, 26 Reg_R8, Reg_R9, Reg_R10, Reg_R11, Reg_R12, Reg_R13, Reg_R14, Reg_R15,
27 Reg_R8D, Reg_R9D, Reg_R10D, Reg_R11D, Reg_R12D, Reg_R13D, Reg_R14D, Reg_R15D, 27 Reg_R8B, Reg_R9B, Reg_R10B, Reg_R11B, Reg_R12B, Reg_R13B, Reg_R14B, Reg_R15B,
28 Reg_XMM8, Reg_XMM9, Reg_XMM10, Reg_XMM11, Reg_XMM12, Reg_XMM13, Reg_XMM14, Reg_XMM15, 28 Reg_R8W, Reg_R9W, Reg_R10W, Reg_R11W, Reg_R12W, Reg_R13W, Reg_R14W, Reg_R15W,
29 Reg_RIP, 29 Reg_R8D, Reg_R9D, Reg_R10D, Reg_R11D, Reg_R12D, Reg_R13D, Reg_R14D, Reg_R15D,
30 Reg_SIL, Reg_DIL, Reg_BPL, Reg_SPL, 30 Reg_XMM8, Reg_XMM9, Reg_XMM10, Reg_XMM11, Reg_XMM12, Reg_XMM13, Reg_XMM14, Reg_XMM15,
31 31 Reg_RIP,
32 Reg_EFLAGS, 32 Reg_SIL, Reg_DIL, Reg_BPL, Reg_SPL,
33 Reg_CS, 33
34 Reg_DS, 34 Reg_EFLAGS,
35 Reg_SS, 35 Reg_CS,
36 Reg_ES, 36 Reg_DS,
37 Reg_FS, 37 Reg_SS,
38 Reg_GS, 38 Reg_ES,
39 Reg_AX, Reg_BX, Reg_CX, Reg_DX, Reg_SI, Reg_DI, Reg_BP, Reg_SP, 39 Reg_FS,
40 Reg_AL, Reg_AH, Reg_BL, Reg_BH, Reg_CL, Reg_CH, Reg_DL, Reg_DH, 40 Reg_GS,
41 Reg_CR0, Reg_CR2, Reg_CR3, Reg_CR4, 41 Reg_AX, Reg_BX, Reg_CX, Reg_DX, Reg_SI, Reg_DI, Reg_BP, Reg_SP,
42 Reg_DR0, Reg_DR1, Reg_DR2, Reg_DR3, Reg_DR6, Reg_DR7, 42 Reg_AL, Reg_AH, Reg_BL, Reg_BH, Reg_CL, Reg_CH, Reg_DL, Reg_DH,
43 Reg_TR3, Reg_TR4, Reg_TR5, Reg_TR6, Reg_TR7 43 Reg_CR0, Reg_CR2, Reg_CR3, Reg_CR4,
44 } Reg; 44 Reg_DR0, Reg_DR1, Reg_DR2, Reg_DR3, Reg_DR6, Reg_DR7,
45 45 Reg_TR3, Reg_TR4, Reg_TR5, Reg_TR6, Reg_TR7
46 static const int N_Regs = /*gp*/ 8 + /*fp*/ 8 + /*mmx*/ 8 + /*sse*/ 8 + 46 } Reg;
47 /*seg*/ 6 + /*16bit*/ 8 + /*8bit*/ 8 + /*sys*/ 4+6+5 + /*flags*/ + 1 47
48 + 8 /*RAX, etc*/ 48 static const int N_Regs = /*gp*/ 8 + /*fp*/ 8 + /*mmx*/ 8 + /*sse*/ 8 +
49 + 8 /*R8-15*/ 49 /*seg*/ 6 + /*16bit*/ 8 + /*8bit*/ 8 + /*sys*/ 4+6+5 + /*flags*/ + 1
50 + 4 /*SIL, etc. 8-bit*/ 50 + 8 /*RAX, etc*/
51 + 8 /*R8-15B*/ 51 + 8 /*R8-15*/
52 + 8 /*R8-15W*/ 52 + 4 /*SIL, etc. 8-bit*/
53 + 8 /*R8-15D*/ 53 + 8 /*R8-15B*/
54 + 8 /*XMM8-15*/ 54 + 8 /*R8-15W*/
55 + 1 /*RIP*/ 55 + 8 /*R8-15D*/
56 56 + 8 /*XMM8-15*/
57 ; 57 + 1 /*RIP*/
58
59 ;
58 60
59 #define NULL_TREE "" 61 #define NULL_TREE ""
60 62
61 static struct { 63 static struct
62 const char * name; 64 {
63 std::string gccName; // GAS will take upper case, but GCC won't (needed for the clobber list) 65 const char * name;
64 Identifier * ident; 66 std::string gccName; // GAS will take upper case, but GCC won't (needed for the clobber list)
65 char size; 67 Identifier * ident;
66 char baseReg; // %% todo: Reg, Reg_XX 68 char size;
67 } regInfo[N_Regs] = { 69 char baseReg; // %% todo: Reg, Reg_XX
68 { "EAX", NULL_TREE, NULL, 4, Reg_EAX }, 70 } regInfo[N_Regs] =
69 { "EBX", NULL_TREE, NULL, 4, Reg_EBX }, 71 {
70 { "ECX", NULL_TREE, NULL, 4, Reg_ECX }, 72 { "EAX", NULL_TREE, NULL, 4, Reg_EAX },
71 { "EDX", NULL_TREE, NULL, 4, Reg_EDX }, 73 { "EBX", NULL_TREE, NULL, 4, Reg_EBX },
72 { "ESI", NULL_TREE, NULL, 4, Reg_ESI }, 74 { "ECX", NULL_TREE, NULL, 4, Reg_ECX },
73 { "EDI", NULL_TREE, NULL, 4, Reg_EDI }, 75 { "EDX", NULL_TREE, NULL, 4, Reg_EDX },
74 { "EBP", NULL_TREE, NULL, 4, Reg_EBP }, 76 { "ESI", NULL_TREE, NULL, 4, Reg_ESI },
75 { "ESP", NULL_TREE, NULL, 4, Reg_ESP }, 77 { "EDI", NULL_TREE, NULL, 4, Reg_EDI },
76 { "ST", NULL_TREE, NULL, 10, Reg_ST }, 78 { "EBP", NULL_TREE, NULL, 4, Reg_EBP },
77 { "ST(1)", NULL_TREE, NULL,10, Reg_ST1 }, 79 { "ESP", NULL_TREE, NULL, 4, Reg_ESP },
78 { "ST(2)", NULL_TREE, NULL,10, Reg_ST2 }, 80 { "ST", NULL_TREE, NULL, 10, Reg_ST },
79 { "ST(3)", NULL_TREE, NULL,10, Reg_ST3 }, 81 { "ST(1)", NULL_TREE, NULL,10, Reg_ST1 },
80 { "ST(4)", NULL_TREE, NULL,10, Reg_ST4 }, 82 { "ST(2)", NULL_TREE, NULL,10, Reg_ST2 },
81 { "ST(5)", NULL_TREE, NULL,10, Reg_ST5 }, 83 { "ST(3)", NULL_TREE, NULL,10, Reg_ST3 },
82 { "ST(6)", NULL_TREE, NULL,10, Reg_ST6 }, 84 { "ST(4)", NULL_TREE, NULL,10, Reg_ST4 },
83 { "ST(7)", NULL_TREE, NULL,10, Reg_ST7 }, 85 { "ST(5)", NULL_TREE, NULL,10, Reg_ST5 },
84 { "MM0", NULL_TREE, NULL, 8, Reg_MM0 }, 86 { "ST(6)", NULL_TREE, NULL,10, Reg_ST6 },
85 { "MM1", NULL_TREE, NULL, 8, Reg_MM1 }, 87 { "ST(7)", NULL_TREE, NULL,10, Reg_ST7 },
86 { "MM2", NULL_TREE, NULL, 8, Reg_MM2 }, 88 { "MM0", NULL_TREE, NULL, 8, Reg_MM0 },
87 { "MM3", NULL_TREE, NULL, 8, Reg_MM3 }, 89 { "MM1", NULL_TREE, NULL, 8, Reg_MM1 },
88 { "MM4", NULL_TREE, NULL, 8, Reg_MM4 }, 90 { "MM2", NULL_TREE, NULL, 8, Reg_MM2 },
89 { "MM5", NULL_TREE, NULL, 8, Reg_MM5 }, 91 { "MM3", NULL_TREE, NULL, 8, Reg_MM3 },
90 { "MM6", NULL_TREE, NULL, 8, Reg_MM6 }, 92 { "MM4", NULL_TREE, NULL, 8, Reg_MM4 },
91 { "MM7", NULL_TREE, NULL, 8, Reg_MM7 }, 93 { "MM5", NULL_TREE, NULL, 8, Reg_MM5 },
92 { "XMM0", NULL_TREE, NULL, 16, Reg_XMM0 }, 94 { "MM6", NULL_TREE, NULL, 8, Reg_MM6 },
93 { "XMM1", NULL_TREE, NULL, 16, Reg_XMM1 }, 95 { "MM7", NULL_TREE, NULL, 8, Reg_MM7 },
94 { "XMM2", NULL_TREE, NULL, 16, Reg_XMM2 }, 96 { "XMM0", NULL_TREE, NULL, 16, Reg_XMM0 },
95 { "XMM3", NULL_TREE, NULL, 16, Reg_XMM3 }, 97 { "XMM1", NULL_TREE, NULL, 16, Reg_XMM1 },
96 { "XMM4", NULL_TREE, NULL, 16, Reg_XMM4 }, 98 { "XMM2", NULL_TREE, NULL, 16, Reg_XMM2 },
97 { "XMM5", NULL_TREE, NULL, 16, Reg_XMM5 }, 99 { "XMM3", NULL_TREE, NULL, 16, Reg_XMM3 },
98 { "XMM6", NULL_TREE, NULL, 16, Reg_XMM6 }, 100 { "XMM4", NULL_TREE, NULL, 16, Reg_XMM4 },
99 { "XMM7", NULL_TREE, NULL, 16, Reg_XMM7 }, 101 { "XMM5", NULL_TREE, NULL, 16, Reg_XMM5 },
100 102 { "XMM6", NULL_TREE, NULL, 16, Reg_XMM6 },
101 { "RAX", NULL_TREE, NULL, 8, Reg_RAX }, 103 { "XMM7", NULL_TREE, NULL, 16, Reg_XMM7 },
102 { "RBX", NULL_TREE, NULL, 8, Reg_RBX }, 104
103 { "RCX", NULL_TREE, NULL, 8, Reg_RCX }, 105 { "RAX", NULL_TREE, NULL, 8, Reg_RAX },
104 { "RDX", NULL_TREE, NULL, 8, Reg_RDX }, 106 { "RBX", NULL_TREE, NULL, 8, Reg_RBX },
105 { "RSI", NULL_TREE, NULL, 8, Reg_RSI }, 107 { "RCX", NULL_TREE, NULL, 8, Reg_RCX },
106 { "RDI", NULL_TREE, NULL, 8, Reg_RDI }, 108 { "RDX", NULL_TREE, NULL, 8, Reg_RDX },
107 { "RBP", NULL_TREE, NULL, 8, Reg_RBP }, 109 { "RSI", NULL_TREE, NULL, 8, Reg_RSI },
108 { "RSP", NULL_TREE, NULL, 8, Reg_RSP }, 110 { "RDI", NULL_TREE, NULL, 8, Reg_RDI },
109 { "R8", NULL_TREE, NULL, 8, Reg_R8 }, 111 { "RBP", NULL_TREE, NULL, 8, Reg_RBP },
110 { "R9", NULL_TREE, NULL, 8, Reg_R9 }, 112 { "RSP", NULL_TREE, NULL, 8, Reg_RSP },
111 { "R10", NULL_TREE, NULL, 8, Reg_R10 }, 113 { "R8", NULL_TREE, NULL, 8, Reg_R8 },
112 { "R11", NULL_TREE, NULL, 8, Reg_R11 }, 114 { "R9", NULL_TREE, NULL, 8, Reg_R9 },
113 { "R12", NULL_TREE, NULL, 8, Reg_R12 }, 115 { "R10", NULL_TREE, NULL, 8, Reg_R10 },
114 { "R13", NULL_TREE, NULL, 8, Reg_R13 }, 116 { "R11", NULL_TREE, NULL, 8, Reg_R11 },
115 { "R14", NULL_TREE, NULL, 8, Reg_R14 }, 117 { "R12", NULL_TREE, NULL, 8, Reg_R12 },
116 { "R15", NULL_TREE, NULL, 8, Reg_R15 }, 118 { "R13", NULL_TREE, NULL, 8, Reg_R13 },
117 { "R8B", NULL_TREE, NULL, 1, Reg_R8 }, 119 { "R14", NULL_TREE, NULL, 8, Reg_R14 },
118 { "R9B", NULL_TREE, NULL, 1, Reg_R9 }, 120 { "R15", NULL_TREE, NULL, 8, Reg_R15 },
119 { "R10B", NULL_TREE, NULL, 1, Reg_R10 }, 121 { "R8B", NULL_TREE, NULL, 1, Reg_R8 },
120 { "R11B", NULL_TREE, NULL, 1, Reg_R11 }, 122 { "R9B", NULL_TREE, NULL, 1, Reg_R9 },
121 { "R12B", NULL_TREE, NULL, 1, Reg_R12 }, 123 { "R10B", NULL_TREE, NULL, 1, Reg_R10 },
122 { "R13B", NULL_TREE, NULL, 1, Reg_R13 }, 124 { "R11B", NULL_TREE, NULL, 1, Reg_R11 },
123 { "R14B", NULL_TREE, NULL, 1, Reg_R14 }, 125 { "R12B", NULL_TREE, NULL, 1, Reg_R12 },
124 { "R15B", NULL_TREE, NULL, 1, Reg_R15 }, 126 { "R13B", NULL_TREE, NULL, 1, Reg_R13 },
125 { "R8W", NULL_TREE, NULL, 2, Reg_R8 }, 127 { "R14B", NULL_TREE, NULL, 1, Reg_R14 },
126 { "R9W", NULL_TREE, NULL, 2, Reg_R9 }, 128 { "R15B", NULL_TREE, NULL, 1, Reg_R15 },
127 { "R10W", NULL_TREE, NULL, 2, Reg_R10 }, 129 { "R8W", NULL_TREE, NULL, 2, Reg_R8 },
128 { "R11W", NULL_TREE, NULL, 2, Reg_R11 }, 130 { "R9W", NULL_TREE, NULL, 2, Reg_R9 },
129 { "R12W", NULL_TREE, NULL, 2, Reg_R12 }, 131 { "R10W", NULL_TREE, NULL, 2, Reg_R10 },
130 { "R13W", NULL_TREE, NULL, 2, Reg_R13 }, 132 { "R11W", NULL_TREE, NULL, 2, Reg_R11 },
131 { "R14W", NULL_TREE, NULL, 2, Reg_R14 }, 133 { "R12W", NULL_TREE, NULL, 2, Reg_R12 },
132 { "R15W", NULL_TREE, NULL, 2, Reg_R15 }, 134 { "R13W", NULL_TREE, NULL, 2, Reg_R13 },
133 { "R8D", NULL_TREE, NULL, 4, Reg_R8 }, 135 { "R14W", NULL_TREE, NULL, 2, Reg_R14 },
134 { "R9D", NULL_TREE, NULL, 4, Reg_R9 }, 136 { "R15W", NULL_TREE, NULL, 2, Reg_R15 },
135 { "R10D", NULL_TREE, NULL, 4, Reg_R10 }, 137 { "R8D", NULL_TREE, NULL, 4, Reg_R8 },
136 { "R11D", NULL_TREE, NULL, 4, Reg_R11 }, 138 { "R9D", NULL_TREE, NULL, 4, Reg_R9 },
137 { "R12D", NULL_TREE, NULL, 4, Reg_R12 }, 139 { "R10D", NULL_TREE, NULL, 4, Reg_R10 },
138 { "R13D", NULL_TREE, NULL, 4, Reg_R13 }, 140 { "R11D", NULL_TREE, NULL, 4, Reg_R11 },
139 { "R14D", NULL_TREE, NULL, 4, Reg_R14 }, 141 { "R12D", NULL_TREE, NULL, 4, Reg_R12 },
140 { "R15D", NULL_TREE, NULL, 4, Reg_R15 }, 142 { "R13D", NULL_TREE, NULL, 4, Reg_R13 },
141 { "XMM8", NULL_TREE, NULL, 16, Reg_XMM8 }, 143 { "R14D", NULL_TREE, NULL, 4, Reg_R14 },
142 { "XMM9", NULL_TREE, NULL, 16, Reg_XMM9 }, 144 { "R15D", NULL_TREE, NULL, 4, Reg_R15 },
143 { "XMM10", NULL_TREE, NULL, 16, Reg_XMM10 }, 145 { "XMM8", NULL_TREE, NULL, 16, Reg_XMM8 },
144 { "XMM11", NULL_TREE, NULL, 16, Reg_XMM11 }, 146 { "XMM9", NULL_TREE, NULL, 16, Reg_XMM9 },
145 { "XMM12", NULL_TREE, NULL, 16, Reg_XMM12 }, 147 { "XMM10", NULL_TREE, NULL, 16, Reg_XMM10 },
146 { "XMM13", NULL_TREE, NULL, 16, Reg_XMM13 }, 148 { "XMM11", NULL_TREE, NULL, 16, Reg_XMM11 },
147 { "XMM14", NULL_TREE, NULL, 16, Reg_XMM14 }, 149 { "XMM12", NULL_TREE, NULL, 16, Reg_XMM12 },
148 { "XMM15", NULL_TREE, NULL, 16, Reg_XMM15 }, 150 { "XMM13", NULL_TREE, NULL, 16, Reg_XMM13 },
149 { "RIP", NULL_TREE, NULL, 8, Reg_RIP }, 151 { "XMM14", NULL_TREE, NULL, 16, Reg_XMM14 },
150 { "SIL", NULL_TREE, NULL, 1, Reg_SIL }, 152 { "XMM15", NULL_TREE, NULL, 16, Reg_XMM15 },
151 { "DIL", NULL_TREE, NULL, 1, Reg_DIL }, 153 { "RIP", NULL_TREE, NULL, 8, Reg_RIP },
152 { "BPL", NULL_TREE, NULL, 1, Reg_BPL }, 154 { "SIL", NULL_TREE, NULL, 1, Reg_SIL },
153 { "SPL", NULL_TREE, NULL, 1, Reg_SPL }, 155 { "DIL", NULL_TREE, NULL, 1, Reg_DIL },
154 156 { "BPL", NULL_TREE, NULL, 1, Reg_BPL },
155 { "FLAGS", NULL_TREE, NULL, 0, Reg_EFLAGS }, // the gcc name is "flags"; not used in assembler input 157 { "SPL", NULL_TREE, NULL, 1, Reg_SPL },
156 { "CS", NULL_TREE, NULL, 2, -1 }, 158
157 { "DS", NULL_TREE, NULL, 2, -1 }, 159 { "FLAGS", NULL_TREE, NULL, 0, Reg_EFLAGS }, // the gcc name is "flags"; not used in assembler input
158 { "SS", NULL_TREE, NULL, 2, -1 }, 160 { "CS", NULL_TREE, NULL, 2, -1 },
159 { "ES", NULL_TREE, NULL, 2, -1 }, 161 { "DS", NULL_TREE, NULL, 2, -1 },
160 { "FS", NULL_TREE, NULL, 2, -1 }, 162 { "SS", NULL_TREE, NULL, 2, -1 },
161 { "GS", NULL_TREE, NULL, 2, -1 }, 163 { "ES", NULL_TREE, NULL, 2, -1 },
162 { "AX", NULL_TREE, NULL, 2, Reg_EAX }, 164 { "FS", NULL_TREE, NULL, 2, -1 },
163 { "BX", NULL_TREE, NULL, 2, Reg_EBX }, 165 { "GS", NULL_TREE, NULL, 2, -1 },
164 { "CX", NULL_TREE, NULL, 2, Reg_ECX }, 166 { "AX", NULL_TREE, NULL, 2, Reg_EAX },
165 { "DX", NULL_TREE, NULL, 2, Reg_EDX }, 167 { "BX", NULL_TREE, NULL, 2, Reg_EBX },
166 { "SI", NULL_TREE, NULL, 2, Reg_ESI }, 168 { "CX", NULL_TREE, NULL, 2, Reg_ECX },
167 { "DI", NULL_TREE, NULL, 2, Reg_EDI }, 169 { "DX", NULL_TREE, NULL, 2, Reg_EDX },
168 { "BP", NULL_TREE, NULL, 2, Reg_EBP }, 170 { "SI", NULL_TREE, NULL, 2, Reg_ESI },
169 { "SP", NULL_TREE, NULL, 2, Reg_ESP }, 171 { "DI", NULL_TREE, NULL, 2, Reg_EDI },
170 { "AL", NULL_TREE, NULL, 1, Reg_EAX }, 172 { "BP", NULL_TREE, NULL, 2, Reg_EBP },
171 { "AH", NULL_TREE, NULL, 1, Reg_EAX }, 173 { "SP", NULL_TREE, NULL, 2, Reg_ESP },
172 { "BL", NULL_TREE, NULL, 1, Reg_EBX }, 174 { "AL", NULL_TREE, NULL, 1, Reg_EAX },
173 { "BH", NULL_TREE, NULL, 1, Reg_EBX }, 175 { "AH", NULL_TREE, NULL, 1, Reg_EAX },
174 { "CL", NULL_TREE, NULL, 1, Reg_ECX }, 176 { "BL", NULL_TREE, NULL, 1, Reg_EBX },
175 { "CH", NULL_TREE, NULL, 1, Reg_ECX }, 177 { "BH", NULL_TREE, NULL, 1, Reg_EBX },
176 { "DL", NULL_TREE, NULL, 1, Reg_EDX }, 178 { "CL", NULL_TREE, NULL, 1, Reg_ECX },
177 { "DH", NULL_TREE, NULL, 1, Reg_EDX }, 179 { "CH", NULL_TREE, NULL, 1, Reg_ECX },
178 { "CR0", NULL_TREE, NULL, 0, -1 }, 180 { "DL", NULL_TREE, NULL, 1, Reg_EDX },
179 { "CR2", NULL_TREE, NULL, 0, -1 }, 181 { "DH", NULL_TREE, NULL, 1, Reg_EDX },
180 { "CR3", NULL_TREE, NULL, 0, -1 }, 182 { "CR0", NULL_TREE, NULL, 0, -1 },
181 { "CR4", NULL_TREE, NULL, 0, -1 }, 183 { "CR2", NULL_TREE, NULL, 0, -1 },
182 { "DR0", NULL_TREE, NULL, 0, -1 }, 184 { "CR3", NULL_TREE, NULL, 0, -1 },
183 { "DR1", NULL_TREE, NULL, 0, -1 }, 185 { "CR4", NULL_TREE, NULL, 0, -1 },
184 { "DR2", NULL_TREE, NULL, 0, -1 }, 186 { "DR0", NULL_TREE, NULL, 0, -1 },
185 { "DR3", NULL_TREE, NULL, 0, -1 }, 187 { "DR1", NULL_TREE, NULL, 0, -1 },
186 { "DR6", NULL_TREE, NULL, 0, -1 }, 188 { "DR2", NULL_TREE, NULL, 0, -1 },
187 { "DR7", NULL_TREE, NULL, 0, -1 }, 189 { "DR3", NULL_TREE, NULL, 0, -1 },
188 { "TR3", NULL_TREE, NULL, 0, -1 }, 190 { "DR6", NULL_TREE, NULL, 0, -1 },
189 { "TR4", NULL_TREE, NULL, 0, -1 }, 191 { "DR7", NULL_TREE, NULL, 0, -1 },
190 { "TR5", NULL_TREE, NULL, 0, -1 }, 192 { "TR3", NULL_TREE, NULL, 0, -1 },
191 { "TR6", NULL_TREE, NULL, 0, -1 }, 193 { "TR4", NULL_TREE, NULL, 0, -1 },
192 { "TR7", NULL_TREE, NULL, 0, -1 } 194 { "TR5", NULL_TREE, NULL, 0, -1 },
193 }; 195 { "TR6", NULL_TREE, NULL, 0, -1 },
194 196 { "TR7", NULL_TREE, NULL, 0, -1 }
195 typedef enum { 197 };
196 No_Type_Needed, 198
197 Int_Types, 199 typedef enum
198 Word_Types, // same as Int_Types, but byte is not allowed 200 {
199 FP_Types, 201 No_Type_Needed,
200 FPInt_Types, 202 Int_Types,
201 Byte_NoType, // byte only, but no type suffix 203 Word_Types, // same as Int_Types, but byte is not allowed
202 } TypeNeeded; 204 FP_Types,
203 205 FPInt_Types,
204 typedef enum { 206 Byte_NoType, // byte only, but no type suffix
205 No_Link, 207 } TypeNeeded;
206 Out_Mnemonic, 208
207 Next_Form 209 typedef enum
208 } OpLink; 210 {
209 211 No_Link,
210 typedef enum { 212 Out_Mnemonic,
211 Clb_SizeAX = 0x01, 213 Next_Form
212 Clb_SizeDXAX = 0x02, 214 } OpLink;
213 Clb_EAX = 0x03, 215
214 Clb_DXAX_Mask = 0x03, 216 typedef enum
215 217 {
216 Clb_Flags = 0x04, 218 Clb_SizeAX = 0x01,
217 Clb_DI = 0x08, 219 Clb_SizeDXAX = 0x02,
218 Clb_SI = 0x10, 220 Clb_EAX = 0x03,
219 Clb_CX = 0x20, 221 Clb_DXAX_Mask = 0x03,
220 Clb_ST = 0x40, 222
221 Clb_SP = 0x80 // Doesn't actually let GCC know the frame pointer is modified 223 Clb_Flags = 0x04,
222 } ImplicitClober; 224 Clb_DI = 0x08,
225 Clb_SI = 0x10,
226 Clb_CX = 0x20,
227 Clb_ST = 0x40,
228 Clb_SP = 0x80 // Doesn't actually let GCC know the frame pointer is modified
229 } ImplicitClober;
223 230
224 // "^ +/..\([A-Za-z_0-9]+\).*" -> " \1," 231 // "^ +/..\([A-Za-z_0-9]+\).*" -> " \1,"
225 typedef enum { 232 typedef enum
226 Op_Invalid, 233 {
227 Op_Adjust, 234 Op_Invalid,
228 Op_Dst, 235 Op_Adjust,
229 Op_Upd, 236 Op_Dst,
230 Op_DstW, 237 Op_Upd,
231 Op_DstF, 238 Op_DstW,
232 Op_UpdF, 239 Op_DstF,
233 Op_DstSrc, 240 Op_UpdF,
234 Op_DstSrcF, 241 Op_DstSrc,
235 Op_UpdSrcF, 242 Op_DstSrcF,
236 Op_DstSrcFW, 243 Op_UpdSrcF,
237 Op_UpdSrcFW, 244 Op_DstSrcFW,
238 Op_DstSrcSSE, 245 Op_UpdSrcFW,
239 Op_DstSrcMMX, 246 Op_DstSrcSSE,
240 Op_DstSrcImmS, 247 Op_DstSrcMMX,
241 Op_DstSrcImmM, 248 Op_DstSrcImmS,
242 Op_UpdSrcShft, 249 Op_DstSrcImmM,
243 Op_DstSrcNT, 250 Op_UpdSrcShft,
244 Op_UpdSrcNT, 251 Op_DstSrcNT,
245 Op_DstMemNT, 252 Op_UpdSrcNT,
246 Op_DstRMBNT, 253 Op_DstMemNT,
247 Op_DstRMWNT, 254 Op_DstRMBNT,
248 Op_UpdUpd, 255 Op_DstRMWNT,
249 Op_UpdUpdF, 256 Op_UpdUpd,
250 Op_Src, 257 Op_UpdUpdF,
251 Op_SrcRMWNT, 258 Op_Src,
252 Op_SrcW, 259 Op_SrcRMWNT,
253 Op_SrcImm, 260 Op_SrcW,
254 Op_Src_DXAXF, 261 Op_SrcImm,
255 Op_SrcMemNT, 262 Op_Src_DXAXF,
256 Op_SrcMemNTF, 263 Op_SrcMemNT,
257 Op_SrcSrc, 264 Op_SrcMemNTF,
258 Op_SrcSrcF, 265 Op_SrcSrc,
259 Op_SrcSrcFW, 266 Op_SrcSrcF,
260 Op_SrcSrcSSEF, 267 Op_SrcSrcFW,
261 Op_SrcSrcMMX, 268 Op_SrcSrcSSEF,
262 Op_Shift, 269 Op_SrcSrcMMX,
263 Op_Branch, 270 Op_Shift,
264 Op_CBranch, 271 Op_Branch,
265 Op_0, 272 Op_CBranch,
266 Op_0_AX, 273 Op_0,
267 Op_0_DXAX, 274 Op_0_AX,
268 Op_Loop, 275 Op_0_DXAX,
269 Op_Flags, 276 Op_Loop,
270 Op_F0_ST, 277 Op_Flags,
271 Op_F0_P, 278 Op_F0_ST,
272 Op_Fs_P, 279 Op_F0_P,
273 Op_Fis, 280 Op_Fs_P,
274 Op_Fis_ST, 281 Op_Fis,
275 Op_Fis_P, 282 Op_Fis_ST,
276 Op_Fid, 283 Op_Fis_P,
277 Op_Fid_P, 284 Op_Fid,
278 Op_Ffd, 285 Op_Fid_P,
279 Op_FfdR, 286 Op_Ffd,
280 Op_Ffd_P, 287 Op_FfdR,
281 Op_FfdR_P, 288 Op_Ffd_P,
282 Op_Fd_P, 289 Op_FfdR_P,
283 Op_FdST, 290 Op_Fd_P,
284 Op_FMath, 291 Op_FdST,
285 Op_FdSTiSTi, 292 Op_FMath,
286 Op_FPMath, 293 Op_FdSTiSTi,
287 Op_FCmp, 294 Op_FPMath,
288 Op_FCmp1, 295 Op_FCmp,
289 Op_FCmpP, 296 Op_FCmp1,
290 Op_FCmpP1, 297 Op_FCmpP,
291 Op_FCmpFlg, 298 Op_FCmpP1,
292 Op_FCmpFlgP, 299 Op_FCmpFlg,
293 Op_fld, 300 Op_FCmpFlgP,
294 Op_fldR, 301 Op_fld,
295 Op_fxch, 302 Op_fldR,
296 Op_fxch1, 303 Op_fxch,
297 Op_fxch0, 304 Op_fxch1,
298 Op_SizedStack, 305 Op_fxch0,
299 Op_bound, 306 Op_SizedStack,
300 Op_bswap, 307 Op_bound,
301 Op_cmps, 308 Op_bswap,
302 Op_cmpsd, 309 Op_cmps,
303 Op_cmpsX, 310 Op_cmpsd,
304 Op_cmpxchg8b, 311 Op_cmpsX,
305 Op_cmpxchg, 312 Op_cmpxchg8b,
306 Op_cpuid, 313 Op_cmpxchg,
307 Op_enter, 314 Op_cpuid,
308 Op_fdisi, 315 Op_enter,
309 Op_feni, 316 Op_fdisi,
310 Op_fsetpm, 317 Op_feni,
311 Op_fXstsw, 318 Op_fsetpm,
312 Op_imul, 319 Op_fXstsw,
313 Op_imul2, 320 Op_imul,
314 Op_imul1, 321 Op_imul2,
315 Op_in, 322 Op_imul1,
316 Op_ins, 323 Op_in,
317 Op_insX, 324 Op_ins,
318 Op_iret, 325 Op_insX,
319 Op_iretd, 326 Op_iret,
320 Op_lods, 327 Op_iretd,
321 Op_lodsX, 328 Op_lods,
322 Op_movs, 329 Op_lodsX,
323 Op_movsd, 330 Op_movs,
324 Op_movsX, 331 Op_movsd,
325 Op_movsx, 332 Op_movsX,
326 Op_movzx, 333 Op_movsx,
327 Op_mul, 334 Op_movzx,
328 Op_out, 335 Op_mul,
329 Op_outs, 336 Op_out,
330 Op_outsX, 337 Op_outs,
331 Op_push, 338 Op_outsX,
332 Op_ret, 339 Op_push,
333 Op_retf, 340 Op_ret,
334 Op_scas, 341 Op_retf,
335 Op_scasX, 342 Op_scas,
336 Op_stos, 343 Op_scasX,
337 Op_stosX, 344 Op_stos,
338 Op_xlat, 345 Op_stosX,
339 N_AsmOpInfo, 346 Op_xlat,
340 Op_Align, 347 N_AsmOpInfo,
341 Op_Even, 348 Op_Align,
342 Op_Naked, 349 Op_Even,
343 Op_db, 350 Op_Naked,
344 Op_ds, 351 Op_db,
345 Op_di, 352 Op_ds,
346 Op_dl, 353 Op_di,
347 Op_df, 354 Op_dl,
348 Op_dd, 355 Op_df,
349 Op_de 356 Op_dd,
350 } AsmOp; 357 Op_de
351 358 } AsmOp;
352 typedef enum { 359
353 Opr_None = 0, 360 typedef enum
354 OprC_MRI = 1, 361 {
355 OprC_MR = 2, 362 Opr_None = 0,
356 OprC_Mem = 3, 363 OprC_MRI = 1,
357 OprC_Reg = 4, 364 OprC_MR = 2,
358 OprC_Imm = 5, 365 OprC_Mem = 3,
359 OprC_SSE = 6, 366 OprC_Reg = 4,
360 OprC_SSE_Mem = 7, 367 OprC_Imm = 5,
361 OprC_R32 = 8, 368 OprC_SSE = 6,
362 OprC_RWord = 9, 369 OprC_SSE_Mem = 7,
363 OprC_RFP = 10, 370 OprC_R32 = 8,
364 OprC_AbsRel = 11, 371 OprC_RWord = 9,
365 OprC_Relative = 12, 372 OprC_RFP = 10,
366 OprC_Port = 13, // DX or imm 373 OprC_AbsRel = 11,
367 OprC_AX = 14, // AL,AX,EAX 374 OprC_Relative = 12,
368 OprC_DX = 15, // only DX 375 OprC_Port = 13, // DX or imm
369 OprC_MMX = 16, 376 OprC_AX = 14, // AL,AX,EAX
370 OprC_MMX_Mem = 17, 377 OprC_DX = 15, // only DX
371 OprC_Shift = 18, // imm or CL 378 OprC_MMX = 16,
372 379 OprC_MMX_Mem = 17,
373 Opr_ClassMask = 0x1f, 380 OprC_Shift = 18, // imm or CL
374 381
375 Opr_Dest = 0x20, 382 Opr_ClassMask = 0x1f,
376 Opr_Update = 0x60, 383
377 384 Opr_Dest = 0x20,
378 Opr_NoType = 0x80, 385 Opr_Update = 0x60,
379 } OprVals; 386
380 387 Opr_NoType = 0x80,
381 388 } OprVals;
382 typedef struct { 389
383 } AsmOprInfo; 390
384 391 typedef struct
385 typedef unsigned char Opr; 392 {
386 393 } AsmOprInfo;
387 typedef struct { 394
388 Opr operands[3]; 395 typedef unsigned char Opr;
389 unsigned char 396
390 needsType : 3, 397 typedef struct
391 implicitClobbers : 8, 398 {
392 linkType : 2; 399 Opr operands[3];
393 unsigned link; 400 unsigned char
394 401 needsType : 3,
395 /* 402 implicitClobbers : 8,
396 bool takesLabel() { 403 linkType : 2;
397 return operands[0] & Opr_Label; 404 unsigned link;
398 } 405
399 */ 406 /*
400 407 bool takesLabel() {
401 unsigned nOperands() { 408 return operands[0] & Opr_Label;
402 if (!operands[0]) 409 }
403 return 0; 410 */
404 else if (!operands[1]) 411
405 return 1; 412 unsigned nOperands()
406 else if (!operands[2]) 413 {
407 return 2; 414 if ( !operands[0] )
408 else 415 return 0;
409 return 3; 416 else if ( !operands[1] )
410 } 417 return 1;
411 } AsmOpInfo; 418 else if ( !operands[2] )
412 419 return 2;
413 typedef enum { 420 else
414 Mn_fdisi, 421 return 3;
415 Mn_feni, 422 }
416 Mn_fsetpm, 423 } AsmOpInfo;
417 Mn_iretw, 424
418 Mn_iret, 425 typedef enum
419 Mn_lret, 426 {
420 Mn_cmpxchg8b, 427 Mn_fdisi,
421 N_AltMn 428 Mn_feni,
422 } Alternate_Mnemonics; 429 Mn_fsetpm,
423 430 Mn_iretw,
424 static const char * alternateMnemonics[N_AltMn] = { 431 Mn_iret,
425 ".byte 0xdb, 0xe1", 432 Mn_lret,
426 ".byte 0xdb, 0xe0", 433 Mn_cmpxchg8b,
427 ".byte 0xdb, 0xe4", 434 N_AltMn
428 "iretw", 435 } Alternate_Mnemonics;
429 "iret", 436
430 "lret", 437 static const char * alternateMnemonics[N_AltMn] =
431 "cmpxchg8b" }; 438 {
439 ".byte 0xdb, 0xe1",
440 ".byte 0xdb, 0xe0",
441 ".byte 0xdb, 0xe4",
442 "iretw",
443 "iret",
444 "lret",
445 "cmpxchg8b"
446 };
432 447
433 #define mri OprC_MRI 448 #define mri OprC_MRI
434 #define mr OprC_MR 449 #define mr OprC_MR
435 #define mem OprC_Mem 450 #define mem OprC_Mem
436 // for now mfp=mem 451 // for now mfp=mem
452 #define U Opr_Update 467 #define U Opr_Update
453 #define N Opr_NoType 468 #define N Opr_NoType
454 //#define L Opr_Label 469 //#define L Opr_Label
455 470
456 // D=dest, N=notype 471 // D=dest, N=notype
457 static AsmOpInfo asmOpInfo[N_AsmOpInfo] = { 472 static AsmOpInfo asmOpInfo[N_AsmOpInfo] =
458 /* Op_Invalid */ {}, 473 {
459 /* Op_Adjust */ { 0,0,0, 0, Clb_EAX /*just AX*/ }, 474 /* Op_Invalid */ {},
460 /* Op_Dst */ { D|mr, 0, 0, 1 }, 475 /* Op_Adjust */ { 0,0,0, 0, Clb_EAX /*just AX*/ },
461 /* Op_Upd */ { U|mr, 0, 0, 1 }, 476 /* Op_Dst */ { D|mr, 0, 0, 1 },
462 /* Op_DstW */ { D|mr, 0, 0, Word_Types }, 477 /* Op_Upd */ { U|mr, 0, 0, 1 },
463 /* Op_DstF */ { D|mr, 0, 0, 1, Clb_Flags }, 478 /* Op_DstW */ { D|mr, 0, 0, Word_Types },
464 /* Op_UpdF */ { U|mr, 0, 0, 1, Clb_Flags }, 479 /* Op_DstF */ { D|mr, 0, 0, 1, Clb_Flags },
465 /* Op_DstSrc */ { D|mr, mri, 0,/**/1 }, 480 /* Op_UpdF */ { U|mr, 0, 0, 1, Clb_Flags },
466 /* Op_DstSrcF */ { D|mr, mri, 0,/**/1, Clb_Flags }, 481 /* Op_DstSrc */ { D|mr, mri, 0,/**/1 },
467 /* Op_UpdSrcF */ { U|mr, mri, 0,/**/1, Clb_Flags }, 482 /* Op_DstSrcF */ { D|mr, mri, 0,/**/1, Clb_Flags },
468 /* Op_DstSrcFW */ { D|mr, mri, 0,/**/Word_Types, Clb_Flags }, 483 /* Op_UpdSrcF */ { U|mr, mri, 0,/**/1, Clb_Flags },
469 /* Op_UpdSrcFW */ { U|mr, mri, 0,/**/Word_Types, Clb_Flags }, 484 /* Op_DstSrcFW */ { D|mr, mri, 0,/**/Word_Types, Clb_Flags },
470 /* Op_DstSrcSSE */ { U|sse, ssem, 0 }, // some may not be update %% 485 /* Op_UpdSrcFW */ { U|mr, mri, 0,/**/Word_Types, Clb_Flags },
471 /* Op_DstSrcMMX */ { U|mmx, mmxm, 0 }, // some may not be update %% 486 /* Op_DstSrcSSE */ { U|sse, ssem, 0 }, // some may not be update %%
472 /* Op_DstSrcImmS*/ { U|sse, ssem, N|imm }, // some may not be update %% 487 /* Op_DstSrcMMX */ { U|mmx, mmxm, 0 }, // some may not be update %%
473 /* Op_DstSrcImmM*/ { U|mmx, mmxm, N|imm }, // some may not be update %% 488 /* Op_DstSrcImmS*/ { U|sse, ssem, N|imm }, // some may not be update %%
474 /* Op_UpdSrcShft*/ { U|mr, reg, N|shft, 1, Clb_Flags }, // 16/32 only 489 /* Op_DstSrcImmM*/ { U|mmx, mmxm, N|imm }, // some may not be update %%
475 /* Op_DstSrcNT */ { D|mr, mr, 0, 0 }, // used for movd .. operands can be rm32,sse,mmx 490 /* Op_UpdSrcShft*/ { U|mr, reg, N|shft, 1, Clb_Flags }, // 16/32 only
476 /* Op_UpdSrcNT */ { U|mr, mr, 0, 0 }, // used for movd .. operands can be rm32,sse,mmx 491 /* Op_DstSrcNT */ { D|mr, mr, 0, 0 }, // used for movd .. operands can be rm32,sse,mmx
477 /* Op_DstMemNT */ { D|mem, 0, 0 }, 492 /* Op_UpdSrcNT */ { U|mr, mr, 0, 0 }, // used for movd .. operands can be rm32,sse,mmx
478 /* Op_DstRMBNT */ { D|mr, 0, 0, Byte_NoType }, 493 /* Op_DstMemNT */ { D|mem, 0, 0 },
479 /* Op_DstRMWNT */ { D|mr, 0, 0 }, 494 /* Op_DstRMBNT */ { D|mr, 0, 0, Byte_NoType },
480 /* Op_UpdUpd */ { U|mr,U|mr, 0,/**/1 }, 495 /* Op_DstRMWNT */ { D|mr, 0, 0 },
481 /* Op_UpdUpdF */ { U|mr,U|mr, 0,/**/1, Clb_Flags }, 496 /* Op_UpdUpd */ { U|mr,U|mr, 0,/**/1 },
482 /* Op_Src */ { mri, 0, 0, 1 }, 497 /* Op_UpdUpdF */ { U|mr,U|mr, 0,/**/1, Clb_Flags },
483 /* Op_SrcRMWNT */ { mr, 0, 0, 0 }, 498 /* Op_Src */ { mri, 0, 0, 1 },
484 /* Op_SrcW */ { mri, 0, 0, Word_Types }, 499 /* Op_SrcRMWNT */ { mr, 0, 0, 0 },
485 /* Op_SrcImm */ { imm }, 500 /* Op_SrcW */ { mri, 0, 0, Word_Types },
486 /* Op_Src_DXAXF */ { mr, 0, 0, 1, Clb_SizeDXAX|Clb_Flags }, 501 /* Op_SrcImm */ { imm },
487 /* Op_SrcMemNT */ { mem, 0, 0 }, 502 /* Op_Src_DXAXF */ { mr, 0, 0, 1, Clb_SizeDXAX|Clb_Flags },
488 /* Op_SrcMemNTF */ { mem, 0, 0, 0, Clb_Flags }, 503 /* Op_SrcMemNT */ { mem, 0, 0 },
489 /* Op_SrcSrc */ { mr, mri, 0, 1 }, 504 /* Op_SrcMemNTF */ { mem, 0, 0, 0, Clb_Flags },
490 /* Op_SrcSrcF */ { mr, mri, 0, 1, Clb_Flags }, 505 /* Op_SrcSrc */ { mr, mri, 0, 1 },
491 /* Op_SrcSrcFW */ { mr, mri, 0, Word_Types, Clb_Flags }, 506 /* Op_SrcSrcF */ { mr, mri, 0, 1, Clb_Flags },
492 /* Op_SrcSrcSSEF*/ { sse, ssem, 0, 0, Clb_Flags }, 507 /* Op_SrcSrcFW */ { mr, mri, 0, Word_Types, Clb_Flags },
493 /* Op_SrcSrcMMX */ { mmx, mmx, 0, }, 508 /* Op_SrcSrcSSEF*/ { sse, ssem, 0, 0, Clb_Flags },
494 /* Op_Shift */ { D|mr,N|shft, 0,/**/1, Clb_Flags }, 509 /* Op_SrcSrcMMX */ { mmx, mmx, 0, },
495 /* Op_Branch */ { mri }, 510 /* Op_Shift */ { D|mr,N|shft, 0,/**/1, Clb_Flags },
496 /* Op_CBranch */ { imm }, 511 /* Op_Branch */ { mri },
497 /* Op_0 */ { 0,0,0 }, 512 /* Op_CBranch */ { imm },
498 /* Op_0_AX */ { 0,0,0, 0, Clb_SizeAX }, 513 /* Op_0 */ { 0,0,0 },
499 /* Op_0_DXAX */ { 0,0,0, 0, Clb_SizeDXAX }, // but for cwd/cdq -- how do know the size.. 514 /* Op_0_AX */ { 0,0,0, 0, Clb_SizeAX },
500 /* Op_Loop */ { imm, 0, 0, 0, Clb_CX }, 515 /* Op_0_DXAX */ { 0,0,0, 0, Clb_SizeDXAX }, // but for cwd/cdq -- how do know the size..
501 /* Op_Flags */ { 0,0,0, 0, Clb_Flags }, 516 /* Op_Loop */ { imm, 0, 0, 0, Clb_CX },
502 /* Op_F0_ST */ { 0,0,0, 0, Clb_ST }, 517 /* Op_Flags */ { 0,0,0, 0, Clb_Flags },
503 /* Op_F0_P */ { 0,0,0, 0, Clb_ST }, // push, pops, etc. not sure how to inform gcc.. 518 /* Op_F0_ST */ { 0,0,0, 0, Clb_ST },
504 /* Op_Fs_P */ { mem, 0, 0, 0, Clb_ST }, // " 519 /* Op_F0_P */ { 0,0,0, 0, Clb_ST }, // push, pops, etc. not sure how to inform gcc..
505 /* Op_Fis */ { mem, 0, 0, FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit 520 /* Op_Fs_P */ { mem, 0, 0, 0, Clb_ST }, // "
506 /* Op_Fis_ST */ { mem, 0, 0, FPInt_Types, Clb_ST }, // " 521 /* Op_Fis */ { mem, 0, 0, FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
507 /* Op_Fis_P */ { mem, 0, 0, FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 522 /* Op_Fis_ST */ { mem, 0, 0, FPInt_Types, Clb_ST }, // "
508 /* Op_Fid */ { D|mem, 0, 0, FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit 523 /* Op_Fis_P */ { mem, 0, 0, FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit
509 /* Op_Fid_P */ { D|mem, 0, 0, FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 524 /* Op_Fid */ { D|mem, 0, 0, FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
510 /* Op_Ffd */ { D|mfp, 0, 0, FP_Types, 0, Next_Form, Op_FfdR }, // only 16bit and 32bit, DMD defaults to 16bit, reg form doesn't need type 525 /* Op_Fid_P */ { D|mem, 0, 0, FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit
511 /* Op_FfdR */ { D|rfp, 0, 0 }, 526 /* Op_Ffd */ { D|mfp, 0, 0, FP_Types, 0, Next_Form, Op_FfdR }, // only 16bit and 32bit, DMD defaults to 16bit, reg form doesn't need type
512 /* Op_Ffd_P */ { D|mfp, 0, 0, FP_Types, Clb_ST, Next_Form, Op_FfdR_P, }, // pop, fld so also 80 bit, " 527 /* Op_FfdR */ { D|rfp, 0, 0 },
513 /* Op_FfdR_P */ { D|rfp, 0, 0, 0, Clb_ST }, 528 /* Op_Ffd_P */ { D|mfp, 0, 0, FP_Types, Clb_ST, Next_Form, Op_FfdR_P, }, // pop, fld so also 80 bit, "
514 /* Op_Fd_P */ { D|mem, 0, 0, 0, Clb_ST }, // " 529 /* Op_FfdR_P */ { D|rfp, 0, 0, 0, Clb_ST },
515 /* Op_FdST */ { D|rfp, 0, 0 }, 530 /* Op_Fd_P */ { D|mem, 0, 0, 0, Clb_ST }, // "
516 /* Op_FMath */ { mfp, 0, 0, FP_Types, Clb_ST, Next_Form, Op_FdSTiSTi }, // and only single or double prec 531 /* Op_FdST */ { D|rfp, 0, 0 },
517 /* Op_FdSTiSTi */ { D|rfp, rfp, 0, }, 532 /* Op_FMath */ { mfp, 0, 0, FP_Types, Clb_ST, Next_Form, Op_FdSTiSTi }, // and only single or double prec
518 /* Op_FPMath */ { D|rfp, rfp, 0, 0, Clb_ST, Next_Form, Op_F0_P }, // pops 533 /* Op_FdSTiSTi */ { D|rfp, rfp, 0, },
519 /* Op_FCmp */ { mfp, 0, 0, FP_Types, 0, Next_Form, Op_FCmp1 }, // DMD defaults to float ptr 534 /* Op_FPMath */ { D|rfp, rfp, 0, 0, Clb_ST, Next_Form, Op_F0_P }, // pops
520 /* Op_FCmp1 */ { rfp, 0, 0, 0, 0, Next_Form, Op_0 }, 535 /* Op_FCmp */ { mfp, 0, 0, FP_Types, 0, Next_Form, Op_FCmp1 }, // DMD defaults to float ptr
521 /* Op_FCmpP */ { mfp, 0, 0, FP_Types, 0, Next_Form, Op_FCmpP1 }, // pops 536 /* Op_FCmp1 */ { rfp, 0, 0, 0, 0, Next_Form, Op_0 },
522 /* Op_FCmpP1 */ { rfp, 0, 0, 0, 0, Next_Form, Op_F0_P }, // pops 537 /* Op_FCmpP */ { mfp, 0, 0, FP_Types, 0, Next_Form, Op_FCmpP1 }, // pops
523 /* Op_FCmpFlg */ { rfp, rfp, 0, 0, Clb_Flags }, 538 /* Op_FCmpP1 */ { rfp, 0, 0, 0, 0, Next_Form, Op_F0_P }, // pops
524 /* Op_FCmpFlgP */ { rfp, rfp, 0, 0, Clb_Flags }, // pops 539 /* Op_FCmpFlg */ { rfp, rfp, 0, 0, Clb_Flags },
525 /* Op_fld */ { mfp, 0, 0, FP_Types, Clb_ST, Next_Form, Op_fldR }, 540 /* Op_FCmpFlgP */ { rfp, rfp, 0, 0, Clb_Flags }, // pops
526 /* Op_fldR */ { rfp, 0, 0, 0, Clb_ST }, 541 /* Op_fld */ { mfp, 0, 0, FP_Types, Clb_ST, Next_Form, Op_fldR },
527 /* Op_fxch */ { D|rfp,D|rfp, 0, 0, Clb_ST, Next_Form, Op_fxch1 }, // not in intel manual?, but DMD allows it (gas won't), second arg must be ST 542 /* Op_fldR */ { rfp, 0, 0, 0, Clb_ST },
528 /* Op_fxch1 */ { D|rfp, 0, 0, 0, Clb_ST, Next_Form, Op_fxch0 }, 543 /* Op_fxch */ { D|rfp,D|rfp, 0, 0, Clb_ST, Next_Form, Op_fxch1 }, // not in intel manual?, but DMD allows it (gas won't), second arg must be ST
529 /* Op_fxch0 */ { 0, 0, 0, 0, Clb_ST }, // Also clobbers ST(1) 544 /* Op_fxch1 */ { D|rfp, 0, 0, 0, Clb_ST, Next_Form, Op_fxch0 },
530 /* Op_SizedStack*/ { 0, 0, 0, 0, Clb_SP }, // type suffix special case 545 /* Op_fxch0 */ { 0, 0, 0, 0, Clb_ST }, // Also clobbers ST(1)
531 /* Op_bound */ { mr, mri, 0, Word_Types }, // operands *not* reversed for gas 546 /* Op_SizedStack*/ { 0, 0, 0, 0, Clb_SP }, // type suffix special case
532 /* Op_bswap */ { D|r32 }, 547 /* Op_bound */ { mr, mri, 0, Word_Types }, // operands *not* reversed for gas
533 /* Op_cmps */ { mem, mem, 0, 1, Clb_DI|Clb_SI|Clb_Flags }, 548 /* Op_bswap */ { D|r32 },
534 /* Op_cmpsd */ { 0, 0, 0, 0, Clb_DI|Clb_SI|Clb_Flags, Next_Form, Op_DstSrcImmS }, 549 /* Op_cmps */ { mem, mem, 0, 1, Clb_DI|Clb_SI|Clb_Flags },
535 /* Op_cmpsX */ { 0, 0, 0, 0, Clb_DI|Clb_SI|Clb_Flags }, 550 /* Op_cmpsd */ { 0, 0, 0, 0, Clb_DI|Clb_SI|Clb_Flags, Next_Form, Op_DstSrcImmS },
536 /* Op_cmpxchg8b */ { D|mem/*64*/,0,0, 0, Clb_SizeDXAX/*32*/|Clb_Flags, Out_Mnemonic, Mn_cmpxchg8b }, 551 /* Op_cmpsX */ { 0, 0, 0, 0, Clb_DI|Clb_SI|Clb_Flags },
537 /* Op_cmpxchg */ { D|mr, reg, 0, 1, Clb_SizeAX|Clb_Flags }, 552 /* Op_cmpxchg8b */ { D|mem/*64*/,0,0, 0, Clb_SizeDXAX/*32*/|Clb_Flags, Out_Mnemonic, Mn_cmpxchg8b },
538 /* Op_cpuid */ { 0,0,0 }, // Clobbers eax, ebx, ecx, and edx. Handled specially below. 553 /* Op_cmpxchg */ { D|mr, reg, 0, 1, Clb_SizeAX|Clb_Flags },
539 /* Op_enter */ { imm, imm }, // operands *not* reversed for gas, %% inform gcc of EBP clobber?, 554 /* Op_cpuid */ { 0,0,0 }, // Clobbers eax, ebx, ecx, and edx. Handled specially below.
540 /* Op_fdisi */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_fdisi }, 555 /* Op_enter */ { imm, imm }, // operands *not* reversed for gas, %% inform gcc of EBP clobber?,
541 /* Op_feni */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_feni }, 556 /* Op_fdisi */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_fdisi },
542 /* Op_fsetpm */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_fsetpm }, 557 /* Op_feni */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_feni },
543 /* Op_fXstsw */ { D|mr, 0, 0, }, // ax is the only allowed register 558 /* Op_fsetpm */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_fsetpm },
544 /* Op_imul */ { D|reg, mr, imm, 1, Clb_Flags, Next_Form, Op_imul2 }, // 16/32 only 559 /* Op_fXstsw */ { D|mr, 0, 0, }, // ax is the only allowed register
545 /* Op_imul2 */ { D|reg, mri, 0, 1, Clb_Flags, Next_Form, Op_imul1 }, // 16/32 only 560 /* Op_imul */ { D|reg, mr, imm, 1, Clb_Flags, Next_Form, Op_imul2 }, // 16/32 only
546 /* Op_imul1 */ { mr, 0, 0, 1, Clb_Flags|Clb_SizeDXAX }, 561 /* Op_imul2 */ { D|reg, mri, 0, 1, Clb_Flags, Next_Form, Op_imul1 }, // 16/32 only
547 /* Op_in */ { D|ax,N|port,0, 1 }, 562 /* Op_imul1 */ { mr, 0, 0, 1, Clb_Flags|Clb_SizeDXAX },
548 /* Op_ins */ { mem,N|dx, 0, 1, Clb_DI }, // can't override ES segment for this one 563 /* Op_in */ { D|ax,N|port,0, 1 },
549 /* Op_insX */ { 0, 0, 0, 0, Clb_DI }, // output segment overrides %% needs work 564 /* Op_ins */ { mem,N|dx, 0, 1, Clb_DI }, // can't override ES segment for this one
550 /* Op_iret */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_iretw }, 565 /* Op_insX */ { 0, 0, 0, 0, Clb_DI }, // output segment overrides %% needs work
551 /* Op_iretd */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_iret }, 566 /* Op_iret */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_iretw },
552 /* Op_lods */ { mem, 0, 0, 1, Clb_SI }, 567 /* Op_iretd */ { 0,0,0, 0, 0, Out_Mnemonic, Mn_iret },
553 /* Op_lodsX */ { 0, 0, 0, 0, Clb_SI }, 568 /* Op_lods */ { mem, 0, 0, 1, Clb_SI },
554 /* Op_movs */ { mem, mem, 0, 1, Clb_DI|Clb_SI }, // only src/DS can be overridden 569 /* Op_lodsX */ { 0, 0, 0, 0, Clb_SI },
555 /* Op_movsd */ { 0, 0, 0, 0, Clb_DI|Clb_SI, Next_Form, Op_DstSrcSSE }, // %% gas doesn't accept movsd .. has to movsl 570 /* Op_movs */ { mem, mem, 0, 1, Clb_DI|Clb_SI }, // only src/DS can be overridden
556 /* Op_movsX */ { 0, 0, 0, 0, Clb_DI|Clb_SI }, 571 /* Op_movsd */ { 0, 0, 0, 0, Clb_DI|Clb_SI, Next_Form, Op_DstSrcSSE }, // %% gas doesn't accept movsd .. has to movsl
557 /* Op_movsx */ { D|reg, mr, 0, 1 }, // type suffix is special case 572 /* Op_movsX */ { 0, 0, 0, 0, Clb_DI|Clb_SI },
558 /* Op_movzx */ { D|reg, mr, 0, 1 }, // type suffix is special case 573 /* Op_movsx */ { D|reg, mr, 0, 1 }, // type suffix is special case
559 /* Op_mul */ { U|ax, mr, 0, 1, Clb_SizeDXAX|Clb_Flags, Next_Form, Op_Src_DXAXF }, 574 /* Op_movzx */ { D|reg, mr, 0, 1 }, // type suffix is special case
560 /* Op_out */ { N|port,ax, 0, 1 }, 575 /* Op_mul */ { U|ax, mr, 0, 1, Clb_SizeDXAX|Clb_Flags, Next_Form, Op_Src_DXAXF },
561 /* Op_outs */ { N|dx, mem, 0, 1, Clb_SI }, 576 /* Op_out */ { N|port,ax, 0, 1 },
562 /* Op_outsX */ { 0, 0, 0, 0, Clb_SI }, 577 /* Op_outs */ { N|dx, mem, 0, 1, Clb_SI },
563 /* Op_push */ { mri, 0, 0, 0, Clb_SP }, // would be Op_SrcW, but DMD defaults to 32-bit for immediate form 578 /* Op_outsX */ { 0, 0, 0, 0, Clb_SI },
564 /* Op_ret */ { imm, 0, 0, 0, 0, Next_Form, Op_0 }, 579 /* Op_push */ { mri, 0, 0, 0, Clb_SP }, // would be Op_SrcW, but DMD defaults to 32-bit for immediate form
565 /* Op_retf */ { 0, 0, 0, 0, 0, Out_Mnemonic, Mn_lret }, 580 /* Op_ret */ { imm, 0, 0, 0, 0, Next_Form, Op_0 },
566 /* Op_scas */ { mem, 0, 0, 1, Clb_DI|Clb_Flags }, 581 /* Op_retf */ { 0, 0, 0, 0, 0, Out_Mnemonic, Mn_lret },
567 /* Op_scasX */ { 0, 0, 0, 0, Clb_DI|Clb_Flags }, 582 /* Op_scas */ { mem, 0, 0, 1, Clb_DI|Clb_Flags },
568 /* Op_stos */ { mem, 0, 0, 1, Clb_DI }, 583 /* Op_scasX */ { 0, 0, 0, 0, Clb_DI|Clb_Flags },
569 /* Op_stosX */ { 0, 0, 0, 0, Clb_DI }, 584 /* Op_stos */ { mem, 0, 0, 1, Clb_DI },
570 /* Op_xlat */ { mem, 0, 0, 0, Clb_SizeAX } 585 /* Op_stosX */ { 0, 0, 0, 0, Clb_DI },
571 586 /* Op_xlat */ { mem, 0, 0, 0, Clb_SizeAX }
572 /// * Op_arpl */ { D|mr, reg }, // 16 only -> DstSrc 587
573 /// * Op_bsX */ { rw, mrw, 0, 1, Clb_Flags },//->srcsrcf 588 /// * Op_arpl */ { D|mr, reg }, // 16 only -> DstSrc
574 /// * Op_bt */ { mrw, riw, 0, 1, Clb_Flags },//->srcsrcf 589 /// * Op_bsX */ { rw, mrw, 0, 1, Clb_Flags },//->srcsrcf
575 /// * Op_btX */ { D|mrw, riw, 0, 1, Clb_Flags },//->dstsrcf .. immediate does not contribute to size 590 /// * Op_bt */ { mrw, riw, 0, 1, Clb_Flags },//->srcsrcf
576 /// * Op_cmovCC */ { D|rw, mrw, 0, 1 } // ->dstsrc 591 /// * Op_btX */ { D|mrw, riw, 0, 1, Clb_Flags },//->dstsrcf .. immediate does not contribute to size
577 }; 592 /// * Op_cmovCC */ { D|rw, mrw, 0, 1 } // ->dstsrc
593 };
578 594
579 #undef mri 595 #undef mri
580 #undef mr 596 #undef mr
581 #undef mem 597 #undef mem
582 #undef mfp 598 #undef mfp
596 #undef D 612 #undef D
597 #undef U 613 #undef U
598 #undef N 614 #undef N
599 //#undef L 615 //#undef L
600 616
601 typedef struct { 617 typedef struct
602 const char * inMnemonic; 618 {
603 AsmOp asmOp; 619 const char * inMnemonic;
604 } AsmOpEnt; 620 AsmOp asmOp;
605 621 } AsmOpEnt;
606 /* Some opcodes which have data size restrictions, but we don't check 622
607 623 /* Some opcodes which have data size restrictions, but we don't check
608 cmov, l<segreg> ?, lea, lsl, shld 624
609 625 cmov, l<segreg> ?, lea, lsl, shld
610 todo: push <immediate> is always the 32-bit form, even tho push <mem> is 16-bit 626
611 */ 627 todo: push <immediate> is always the 32-bit form, even tho push <mem> is 16-bit
612
613 static AsmOpEnt opData[] = {
614 { "adc", Op_UpdSrcF },
615
616 { "add", Op_DstSrcNT }, //Op_UpdSrcF },
617 { "addpd", Op_DstSrcSSE },
618 { "addps", Op_DstSrcSSE },
619 { "addq", Op_DstSrcSSE },
620 { "addsd", Op_DstSrcSSE },
621 { "addss", Op_DstSrcSSE },
622 { "addsubpd", Op_DstSrcSSE },
623 { "addsubps", Op_DstSrcSSE },
624 { "and", Op_UpdSrcF },
625 { "andnpd", Op_DstSrcSSE },
626 { "andnps", Op_DstSrcSSE },
627 { "andpd", Op_DstSrcSSE },
628 { "andps", Op_DstSrcSSE },
629 { "bsf", Op_SrcSrcFW },
630 { "bsr", Op_SrcSrcFW },
631 { "bswap", Op_bswap },
632 { "bt", Op_SrcSrcFW },
633 { "btc", Op_UpdSrcFW },
634 { "btr", Op_UpdSrcFW },
635 { "bts", Op_UpdSrcFW },
636 { "call", Op_Branch },
637 { "callf", Op_Branch },
638 { "cbw", Op_0_AX },
639 { "cdqe", Op_0_DXAX },
640 { "clc", Op_Flags },
641 { "cld", Op_Flags },
642 { "clflush",Op_SrcMemNT },
643 { "cli", Op_Flags },
644 { "clts", Op_0 },
645 { "cmc", Op_Flags },
646 { "cmova", Op_DstSrc },
647 { "cmovae", Op_DstSrc },
648 { "cmovb", Op_DstSrc },
649 { "cmovbe", Op_DstSrc },
650 { "cmovc", Op_DstSrc },
651 { "cmove", Op_DstSrc },
652 { "cmovg", Op_DstSrc },
653 { "cmovge", Op_DstSrc },
654 { "cmovl", Op_DstSrc },
655 { "cmovle", Op_DstSrc },
656 { "cmovna", Op_DstSrc },
657 { "cmovnae",Op_DstSrc },
658 { "cmovnb", Op_DstSrc },
659 { "cmovnbe",Op_DstSrc },
660 { "cmovnc", Op_DstSrc },
661 { "cmovne", Op_DstSrc },
662 { "cmovng", Op_DstSrc },
663 { "cmovnge",Op_DstSrc },
664 { "cmovnl", Op_DstSrc },
665 { "cmovnle",Op_DstSrc },
666 { "cmovno", Op_DstSrc },
667 { "cmovnp", Op_DstSrc },
668 { "cmovns", Op_DstSrc },
669 { "cmovnz", Op_DstSrc },
670 { "cmovo", Op_DstSrc },
671 { "cmovp", Op_DstSrc },
672 { "cmovpe", Op_DstSrc },
673 { "cmovpo", Op_DstSrc },
674 { "cmovs", Op_DstSrc },
675 { "cmovz", Op_DstSrc },
676 { "cmp", Op_SrcSrcF },
677 { "cmppd", Op_DstSrcImmS },
678 { "cmpps", Op_DstSrcImmS },
679 { "cmps", Op_cmps },
680 { "cmpsb", Op_cmpsX },
681 { "cmpsd", Op_cmpsd }, // string cmp, and SSE cmp
682 { "cmpss", Op_DstSrcImmS },
683 { "cmpsw", Op_cmpsX },
684 { "cmpsq", Op_cmpsX },
685 /*
686 { "cdqe", Op_0_DXAX },
687 { "cmpsq", Op_cmpsX },
688 { "cmpxch16b", Op_cmpxchg16b },
689 { "cqo", Op_0_DXAX },
690 { "lodsq", Op_lodsX },
691 { "movsq", Op_movsX },
692 { "popfq", Op_SizedStack },
693 { "pushfq", Op_SizedStack },
694 { "scasq", Op_scasX },
695 { "stosq", Op_stosX },
696 { "iretq", Op_iretd },
697 { "swapgs", Op_0 },
698 { "extrq", Op_Extrq },
699 { "movsxq", Op_movsxq },
700
701 { "clgi", Op_Flags },
702 { "invlpga", Op_SrcMemNT },
703 { "rdtscp", Op_0_DXAX },
704 { "stgi", Op_Flags },
705 { "sysret", Op_0 },
706 */ 628 */
707 629
708 { "cmpxch16b", Op_cmpxchg8b }, 630 static AsmOpEnt opData[] =
709 { "cmpxch8b", Op_cmpxchg8b }, // %% DMD opcode typo? 631 {
710 { "cmpxchg", Op_cmpxchg }, 632 { "adc", Op_UpdSrcF },
711 { "comisd", Op_SrcSrcSSEF }, 633
712 { "comiss", Op_SrcSrcSSEF }, 634 { "add", Op_DstSrcNT }, //Op_UpdSrcF },
713 { "cpuid", Op_cpuid }, 635 { "addpd", Op_DstSrcSSE },
714 { "cvtdq2pd", Op_DstSrcSSE }, 636 { "addps", Op_DstSrcSSE },
715 { "cvtdq2ps", Op_DstSrcSSE }, 637 { "addq", Op_DstSrcSSE },
716 { "cvtpd2dq", Op_DstSrcSSE }, 638 { "addsd", Op_DstSrcSSE },
717 { "cvtpd2pi", Op_DstSrcSSE }, 639 { "addss", Op_DstSrcSSE },
718 { "cvtpd2ps", Op_DstSrcSSE }, 640 { "addsubpd", Op_DstSrcSSE },
719 { "cvtpi2pd", Op_DstSrcSSE }, 641 { "addsubps", Op_DstSrcSSE },
720 { "cvtpi2ps", Op_DstSrcSSE }, 642 { "and", Op_UpdSrcF },
721 { "cvtps2dq", Op_DstSrcSSE }, 643 { "andnpd", Op_DstSrcSSE },
722 { "cvtps2pd", Op_DstSrcSSE }, 644 { "andnps", Op_DstSrcSSE },
723 { "cvtps2pi", Op_DstSrcSSE }, 645 { "andpd", Op_DstSrcSSE },
724 { "cvtsd2si", Op_DstSrcSSE }, 646 { "andps", Op_DstSrcSSE },
725 { "cvtsd2ss", Op_DstSrcSSE }, 647 { "bsf", Op_SrcSrcFW },
726 { "cvtsi2sd", Op_DstSrcSSE }, 648 { "bsr", Op_SrcSrcFW },
727 { "cvtsi2ss", Op_DstSrcSSE }, 649 { "bswap", Op_bswap },
728 { "cvtss2sd", Op_DstSrcSSE }, 650 { "bt", Op_SrcSrcFW },
729 { "cvtss2si", Op_DstSrcSSE }, 651 { "btc", Op_UpdSrcFW },
730 { "cvttpd2dq", Op_DstSrcSSE }, 652 { "btr", Op_UpdSrcFW },
731 { "cvttpd2pi", Op_DstSrcSSE }, 653 { "bts", Op_UpdSrcFW },
732 { "cvttps2dq", Op_DstSrcSSE }, 654 { "call", Op_Branch },
733 { "cvttps2pi", Op_DstSrcSSE }, 655 { "callf", Op_Branch },
734 { "cvttsd2si", Op_DstSrcSSE }, 656 { "cbw", Op_0_AX },
735 { "cvttss2si", Op_DstSrcSSE }, 657 { "cdqe", Op_0_DXAX },
736 { "cwd", Op_0_DXAX }, 658 { "clc", Op_Flags },
737 { "cwde", Op_0_DXAX }, 659 { "cld", Op_Flags },
738 //{ "da", Op_ },// dunno what this is -- takes labels? 660 { "clflush",Op_SrcMemNT },
739 { "db", Op_db }, 661 { "cli", Op_Flags },
740 { "dd", Op_dd }, 662 { "clts", Op_0 },
741 { "de", Op_de }, 663 { "cmc", Op_Flags },
742 { "dec", Op_UpdF }, 664 { "cmova", Op_DstSrc },
743 { "df", Op_df }, 665 { "cmovae", Op_DstSrc },
744 { "di", Op_di }, 666 { "cmovb", Op_DstSrc },
745 { "div", Op_Src_DXAXF }, 667 { "cmovbe", Op_DstSrc },
746 { "divpd", Op_DstSrcSSE }, 668 { "cmovc", Op_DstSrc },
747 { "divps", Op_DstSrcSSE }, 669 { "cmove", Op_DstSrc },
748 { "divsd", Op_DstSrcSSE }, 670 { "cmovg", Op_DstSrc },
749 { "divss", Op_DstSrcSSE }, 671 { "cmovge", Op_DstSrc },
750 { "dl", Op_dl }, 672 { "cmovl", Op_DstSrc },
751 { "dq", Op_dl }, 673 { "cmovle", Op_DstSrc },
752 { "ds", Op_ds }, 674 { "cmovna", Op_DstSrc },
753 { "dt", Op_de }, 675 { "cmovnae",Op_DstSrc },
754 { "dw", Op_ds }, 676 { "cmovnb", Op_DstSrc },
755 { "emms", Op_0 }, // clobber all mmx/fp? 677 { "cmovnbe",Op_DstSrc },
756 { "enter", Op_enter }, 678 { "cmovnc", Op_DstSrc },
757 { "f2xm1", Op_F0_ST }, // %% most of these are update... 679 { "cmovne", Op_DstSrc },
758 { "fabs", Op_F0_ST }, 680 { "cmovng", Op_DstSrc },
759 { "fadd", Op_FMath }, 681 { "cmovnge",Op_DstSrc },
760 { "faddp", Op_FPMath }, 682 { "cmovnl", Op_DstSrc },
761 { "fbld", Op_Fs_P }, 683 { "cmovnle",Op_DstSrc },
762 { "fbstp", Op_Fd_P }, 684 { "cmovno", Op_DstSrc },
763 { "fchs", Op_F0_ST }, 685 { "cmovnp", Op_DstSrc },
764 { "fclex", Op_0 }, 686 { "cmovns", Op_DstSrc },
765 { "fcmovb", Op_FdSTiSTi }, // but only ST(0) can be the destination -- should be FdST0STi 687 { "cmovnz", Op_DstSrc },
766 { "fcmovbe", Op_FdSTiSTi }, 688 { "cmovo", Op_DstSrc },
767 { "fcmove", Op_FdSTiSTi }, 689 { "cmovp", Op_DstSrc },
768 { "fcmovnb", Op_FdSTiSTi }, 690 { "cmovpe", Op_DstSrc },
769 { "fcmovnbe", Op_FdSTiSTi }, 691 { "cmovpo", Op_DstSrc },
770 { "fcmovne", Op_FdSTiSTi }, 692 { "cmovs", Op_DstSrc },
771 { "fcmovnu", Op_FdSTiSTi }, 693 { "cmovz", Op_DstSrc },
772 { "fcmovu", Op_FdSTiSTi }, 694 { "cmp", Op_SrcSrcF },
773 { "fcom", Op_FCmp }, 695 { "cmppd", Op_DstSrcImmS },
774 { "fcomi", Op_FCmpFlg }, 696 { "cmpps", Op_DstSrcImmS },
775 { "fcomip", Op_FCmpFlgP }, 697 { "cmps", Op_cmps },
776 { "fcomp", Op_FCmpP }, 698 { "cmpsb", Op_cmpsX },
777 { "fcompp", Op_F0_P }, // pops twice 699 { "cmpsd", Op_cmpsd }, // string cmp, and SSE cmp
778 { "fcos", Op_F0_ST }, 700 { "cmpss", Op_DstSrcImmS },
779 { "fdecstp",Op_F0_P }, // changes stack 701 { "cmpsw", Op_cmpsX },
780 { "fdisi", Op_fdisi }, 702 { "cmpsq", Op_cmpsX },
781 { "fdiv", Op_FMath }, 703 /*
782 { "fdivp", Op_FPMath }, 704 { "cdqe", Op_0_DXAX },
783 { "fdivr", Op_FMath }, 705 { "cmpsq", Op_cmpsX },
784 { "fdivrp", Op_FPMath }, 706 { "cmpxch16b", Op_cmpxchg16b },
785 { "feni", Op_feni }, 707 { "cqo", Op_0_DXAX },
786 { "ffree", Op_FdST }, 708 { "lodsq", Op_lodsX },
787 { "fiadd", Op_Fis_ST }, 709 { "movsq", Op_movsX },
788 { "ficom", Op_Fis }, 710 { "popfq", Op_SizedStack },
789 { "ficomp", Op_Fis_P }, 711 { "pushfq", Op_SizedStack },
790 { "fidiv", Op_Fis_ST }, 712 { "scasq", Op_scasX },
791 { "fidivr", Op_Fis_ST }, 713 { "stosq", Op_stosX },
792 { "fild", Op_Fis_P }, 714 { "iretq", Op_iretd },
793 { "fimul", Op_Fis_ST }, 715 { "swapgs", Op_0 },
794 { "fincstp",Op_F0_P }, 716 { "extrq", Op_Extrq },
795 { "finit", Op_F0_P }, 717 { "movsxq", Op_movsxq },
796 { "fist", Op_Fid }, // only 16,32bit 718
797 { "fistp", Op_Fid_P }, 719 { "clgi", Op_Flags },
798 { "fisttp", Op_Fid_P }, 720 { "invlpga", Op_SrcMemNT },
799 { "fisub", Op_Fis_ST }, 721 { "rdtscp", Op_0_DXAX },
800 { "fisubr", Op_Fis_ST }, 722 { "stgi", Op_Flags },
801 { "fld", Op_fld }, 723 { "sysret", Op_0 },
802 { "fld1", Op_F0_P }, 724 */
803 { "fldcw", Op_SrcMemNT }, 725
804 { "fldenv", Op_SrcMemNT }, 726 { "cmpxch16b", Op_cmpxchg8b },
805 { "fldl2e", Op_F0_P }, 727 { "cmpxch8b", Op_cmpxchg8b }, // %% DMD opcode typo?
806 { "fldl2t", Op_F0_P }, 728 { "cmpxchg", Op_cmpxchg },
807 { "fldlg2", Op_F0_P }, 729 { "comisd", Op_SrcSrcSSEF },
808 { "fldln2", Op_F0_P }, 730 { "comiss", Op_SrcSrcSSEF },
809 { "fldpi", Op_F0_P }, 731 { "cpuid", Op_cpuid },
810 { "fldz", Op_F0_P }, 732 { "cvtdq2pd", Op_DstSrcSSE },
811 { "fmul", Op_FMath }, 733 { "cvtdq2ps", Op_DstSrcSSE },
812 { "fmulp", Op_FPMath }, 734 { "cvtpd2dq", Op_DstSrcSSE },
813 { "fnclex", Op_0 }, 735 { "cvtpd2pi", Op_DstSrcSSE },
814 { "fndisi", Op_fdisi }, // ?? 736 { "cvtpd2ps", Op_DstSrcSSE },
815 { "fneni", Op_feni }, // ?? 737 { "cvtpi2pd", Op_DstSrcSSE },
816 { "fninit", Op_0 }, 738 { "cvtpi2ps", Op_DstSrcSSE },
817 { "fnop", Op_0 }, 739 { "cvtps2dq", Op_DstSrcSSE },
818 { "fnsave", Op_DstMemNT }, 740 { "cvtps2pd", Op_DstSrcSSE },
819 { "fnstcw", Op_DstMemNT }, 741 { "cvtps2pi", Op_DstSrcSSE },
820 { "fnstenv",Op_DstMemNT }, 742 { "cvtsd2si", Op_DstSrcSSE },
821 { "fnstsw", Op_fXstsw }, 743 { "cvtsd2ss", Op_DstSrcSSE },
822 { "fpatan", Op_F0_P }, // pop and modify new ST 744 { "cvtsi2sd", Op_DstSrcSSE },
823 { "fprem", Op_F0_ST }, 745 { "cvtsi2ss", Op_DstSrcSSE },
824 { "fprem1", Op_F0_ST }, 746 { "cvtss2sd", Op_DstSrcSSE },
825 { "fptan", Op_F0_P }, // modify ST and push 1.0 747 { "cvtss2si", Op_DstSrcSSE },
826 { "frndint",Op_F0_ST }, 748 { "cvttpd2dq", Op_DstSrcSSE },
827 { "frstor", Op_SrcMemNT }, // but clobbers everything 749 { "cvttpd2pi", Op_DstSrcSSE },
828 { "fsave", Op_DstMemNT }, 750 { "cvttps2dq", Op_DstSrcSSE },
829 { "fscale", Op_F0_ST }, 751 { "cvttps2pi", Op_DstSrcSSE },
830 { "fsetpm", Op_fsetpm }, 752 { "cvttsd2si", Op_DstSrcSSE },
831 { "fsin", Op_F0_ST }, 753 { "cvttss2si", Op_DstSrcSSE },
832 { "fsincos",Op_F0_P }, 754 { "cwd", Op_0_DXAX },
833 { "fsqrt", Op_F0_ST }, 755 { "cwde", Op_0_DXAX },
834 { "fst", Op_Ffd }, 756 //{ "da", Op_ },// dunno what this is -- takes labels?
835 { "fstcw", Op_DstMemNT }, 757 { "db", Op_db },
836 { "fstenv", Op_DstMemNT }, 758 { "dd", Op_dd },
837 { "fstp", Op_Ffd_P }, 759 { "de", Op_de },
838 { "fstsw", Op_fXstsw }, 760 { "dec", Op_UpdF },
839 { "fsub", Op_FMath }, 761 { "df", Op_df },
840 { "fsubp", Op_FPMath }, 762 { "di", Op_di },
841 { "fsubr", Op_FMath }, 763 { "div", Op_Src_DXAXF },
842 { "fsubrp", Op_FPMath }, 764 { "divpd", Op_DstSrcSSE },
843 { "ftst", Op_0 }, 765 { "divps", Op_DstSrcSSE },
844 { "fucom", Op_FCmp }, 766 { "divsd", Op_DstSrcSSE },
845 { "fucomi", Op_FCmpFlg }, 767 { "divss", Op_DstSrcSSE },
846 { "fucomip",Op_FCmpFlgP }, 768 { "dl", Op_dl },
847 { "fucomp", Op_FCmpP }, 769 { "dq", Op_dl },
848 { "fucompp",Op_F0_P }, // pops twice 770 { "ds", Op_ds },
849 { "fwait", Op_0 }, 771 { "dt", Op_de },
850 { "fxam", Op_0 }, 772 { "dw", Op_ds },
851 { "fxch", Op_fxch }, 773 { "emms", Op_0 }, // clobber all mmx/fp?
852 { "fxrstor",Op_SrcMemNT }, // clobbers FP,MMX,SSE 774 { "enter", Op_enter },
853 { "fxsave", Op_DstMemNT }, 775 { "f2xm1", Op_F0_ST }, // %% most of these are update...
854 { "fxtract",Op_F0_P }, // pushes 776 { "fabs", Op_F0_ST },
855 { "fyl2x", Op_F0_P }, // pops 777 { "fadd", Op_FMath },
856 { "fyl2xp1",Op_F0_P }, // pops 778 { "faddp", Op_FPMath },
857 { "haddpd", Op_DstSrcSSE }, 779 { "fbld", Op_Fs_P },
858 { "haddps", Op_DstSrcSSE }, 780 { "fbstp", Op_Fd_P },
859 { "hlt", Op_0 }, 781 { "fchs", Op_F0_ST },
860 { "hsubpd", Op_DstSrcSSE }, 782 { "fclex", Op_0 },
861 { "hsubps", Op_DstSrcSSE }, 783 { "fcmovb", Op_FdSTiSTi }, // but only ST(0) can be the destination -- should be FdST0STi
862 { "idiv", Op_Src_DXAXF }, 784 { "fcmovbe", Op_FdSTiSTi },
863 { "imul", Op_DstSrcNT }, 785 { "fcmove", Op_FdSTiSTi },
864 { "in", Op_in }, 786 { "fcmovnb", Op_FdSTiSTi },
865 { "inc", Op_UpdF }, 787 { "fcmovnbe", Op_FdSTiSTi },
866 { "ins", Op_ins }, 788 { "fcmovne", Op_FdSTiSTi },
867 { "insb", Op_insX }, 789 { "fcmovnu", Op_FdSTiSTi },
868 { "insd", Op_insX }, 790 { "fcmovu", Op_FdSTiSTi },
869 { "insw", Op_insX }, 791 { "fcom", Op_FCmp },
870 { "int", Op_SrcImm }, 792 { "fcomi", Op_FCmpFlg },
871 { "into", Op_0 }, 793 { "fcomip", Op_FCmpFlgP },
872 { "invd", Op_0 }, 794 { "fcomp", Op_FCmpP },
873 { "invlpg", Op_SrcMemNT }, 795 { "fcompp", Op_F0_P }, // pops twice
874 { "iret", Op_iret }, 796 { "fcos", Op_F0_ST },
875 { "iretd", Op_iretd }, 797 { "fdecstp",Op_F0_P }, // changes stack
876 { "iretq", Op_iretd }, 798 { "fdisi", Op_fdisi },
877 { "ja", Op_CBranch }, 799 { "fdiv", Op_FMath },
878 { "jae", Op_CBranch }, 800 { "fdivp", Op_FPMath },
879 { "jb", Op_CBranch }, 801 { "fdivr", Op_FMath },
880 { "jbe", Op_CBranch }, 802 { "fdivrp", Op_FPMath },
881 { "jc", Op_CBranch }, 803 { "feni", Op_feni },
882 { "jcxz", Op_CBranch }, 804 { "ffree", Op_FdST },
883 { "je", Op_CBranch }, 805 { "fiadd", Op_Fis_ST },
884 { "jecxz", Op_CBranch }, 806 { "ficom", Op_Fis },
885 { "jg", Op_CBranch }, 807 { "ficomp", Op_Fis_P },
886 { "jge", Op_CBranch }, 808 { "fidiv", Op_Fis_ST },
887 { "jl", Op_CBranch }, 809 { "fidivr", Op_Fis_ST },
888 { "jle", Op_CBranch }, 810 { "fild", Op_Fis_P },
889 { "jmp", Op_Branch }, 811 { "fimul", Op_Fis_ST },
890 { "jmpe", Op_Branch }, 812 { "fincstp",Op_F0_P },
891 { "jmpf", Op_Branch }, 813 { "finit", Op_F0_P },
892 { "jna", Op_CBranch }, 814 { "fist", Op_Fid }, // only 16,32bit
893 { "jnae", Op_CBranch }, 815 { "fistp", Op_Fid_P },
894 { "jnb", Op_CBranch }, 816 { "fisttp", Op_Fid_P },
895 { "jnbe", Op_CBranch }, 817 { "fisub", Op_Fis_ST },
896 { "jnc", Op_CBranch }, 818 { "fisubr", Op_Fis_ST },
897 { "jne", Op_CBranch }, 819 { "fld", Op_fld },
898 { "jng", Op_CBranch }, 820 { "fld1", Op_F0_P },
899 { "jnge", Op_CBranch }, 821 { "fldcw", Op_SrcMemNT },
900 { "jnl", Op_CBranch }, 822 { "fldenv", Op_SrcMemNT },
901 { "jnle", Op_CBranch }, 823 { "fldl2e", Op_F0_P },
902 { "jno", Op_CBranch }, 824 { "fldl2t", Op_F0_P },
903 { "jnp", Op_CBranch }, 825 { "fldlg2", Op_F0_P },
904 { "jns", Op_CBranch }, 826 { "fldln2", Op_F0_P },
905 { "jnz", Op_CBranch }, 827 { "fldpi", Op_F0_P },
906 { "jo", Op_CBranch }, 828 { "fldz", Op_F0_P },
907 { "jp", Op_CBranch }, 829 { "fmul", Op_FMath },
908 { "jpe", Op_CBranch }, 830 { "fmulp", Op_FPMath },
909 { "jpo", Op_CBranch }, 831 { "fnclex", Op_0 },
910 { "jrcxz", Op_CBranch }, 832 { "fndisi", Op_fdisi }, // ??
911 { "js", Op_CBranch }, 833 { "fneni", Op_feni }, // ??
912 { "jz", Op_CBranch }, 834 { "fninit", Op_0 },
913 { "lahf", Op_0_AX }, 835 { "fnop", Op_0 },
914 { "lar", Op_DstSrcFW }, // reg dest only 836 { "fnsave", Op_DstMemNT },
915 { "lddqu", Op_DstSrcSSE }, 837 { "fnstcw", Op_DstMemNT },
916 { "ldmxcsr", Op_SrcMemNT }, 838 { "fnstenv",Op_DstMemNT },
917 { "lds", Op_DstSrc }, // reg dest only 839 { "fnstsw", Op_fXstsw },
918 { "lea", Op_DstSrc }, // " 840 { "fpatan", Op_F0_P }, // pop and modify new ST
919 { "leaq", Op_DstSrcSSE }, // " 841 { "fprem", Op_F0_ST },
920 { "leave", Op_0 }, // EBP,ESP clobbers 842 { "fprem1", Op_F0_ST },
921 { "lfence",Op_0 }, 843 { "fptan", Op_F0_P }, // modify ST and push 1.0
922 { "lfs", Op_DstSrc }, 844 { "frndint",Op_F0_ST },
923 { "lgdt", Op_SrcMemNT }, 845 { "frstor", Op_SrcMemNT }, // but clobbers everything
924 { "lgs", Op_DstSrc }, 846 { "fsave", Op_DstMemNT },
925 { "lidt", Op_SrcMemNT }, 847 { "fscale", Op_F0_ST },
926 { "lldt", Op_SrcRMWNT }, 848 { "fsetpm", Op_fsetpm },
927 { "lmsw", Op_SrcRMWNT }, 849 { "fsin", Op_F0_ST },
928 { "lock", Op_0 }, 850 { "fsincos",Op_F0_P },
929 { "lods", Op_lods }, 851 { "fsqrt", Op_F0_ST },
930 { "lodsb", Op_lodsX }, 852 { "fst", Op_Ffd },
931 { "lodsd", Op_lodsX }, 853 { "fstcw", Op_DstMemNT },
932 { "lodsw", Op_lodsX }, 854 { "fstenv", Op_DstMemNT },
933 { "lodsq", Op_lodsX }, 855 { "fstp", Op_Ffd_P },
934 { "loop", Op_Loop }, 856 { "fstsw", Op_fXstsw },
935 { "loope", Op_Loop }, 857 { "fsub", Op_FMath },
936 { "loopne",Op_Loop }, 858 { "fsubp", Op_FPMath },
937 { "loopnz",Op_Loop }, 859 { "fsubr", Op_FMath },
938 { "loopz", Op_Loop }, 860 { "fsubrp", Op_FPMath },
939 { "lsl", Op_DstSrcFW }, // reg dest only 861 { "ftst", Op_0 },
940 { "lss", Op_DstSrc }, 862 { "fucom", Op_FCmp },
941 { "ltr", Op_DstMemNT }, 863 { "fucomi", Op_FCmpFlg },
942 { "maskmovdqu", Op_SrcSrcMMX }, // writes to [edi] 864 { "fucomip",Op_FCmpFlgP },
943 { "maskmovq", Op_SrcSrcMMX }, 865 { "fucomp", Op_FCmpP },
944 { "maxpd", Op_DstSrcSSE }, 866 { "fucompp",Op_F0_P }, // pops twice
945 { "maxps", Op_DstSrcSSE }, 867 { "fwait", Op_0 },
946 { "maxsd", Op_DstSrcSSE }, 868 { "fxam", Op_0 },
947 { "maxss", Op_DstSrcSSE }, 869 { "fxch", Op_fxch },
948 { "mfence",Op_0}, 870 { "fxrstor",Op_SrcMemNT }, // clobbers FP,MMX,SSE
949 { "minpd", Op_DstSrcSSE }, 871 { "fxsave", Op_DstMemNT },
950 { "minps", Op_DstSrcSSE }, 872 { "fxtract",Op_F0_P }, // pushes
951 { "minsd", Op_DstSrcSSE }, 873 { "fyl2x", Op_F0_P }, // pops
952 { "minss", Op_DstSrcSSE }, 874 { "fyl2xp1",Op_F0_P }, // pops
953 { "monitor", Op_0 }, 875 { "haddpd", Op_DstSrcSSE },
954 { "mov", Op_DstSrc }, 876 { "haddps", Op_DstSrcSSE },
955 { "movapd", Op_DstSrcSSE }, 877 { "hlt", Op_0 },
956 { "movaps", Op_DstSrcSSE }, 878 { "hsubpd", Op_DstSrcSSE },
957 { "movb", Op_DstSrcNT }, 879 { "hsubps", Op_DstSrcSSE },
958 { "movd", Op_DstSrcNT }, // also mmx and sse 880 { "idiv", Op_Src_DXAXF },
959 { "movddup", Op_DstSrcSSE }, 881 { "imul", Op_DstSrcNT },
960 { "movdq2q", Op_DstSrcNT }, // mmx/sse 882 { "in", Op_in },
961 { "movdqa", Op_DstSrcSSE }, 883 { "inc", Op_UpdF },
962 { "movdqu", Op_DstSrcSSE }, 884 { "ins", Op_ins },
963 { "movhlps", Op_DstSrcSSE }, 885 { "insb", Op_insX },
964 { "movhpd", Op_DstSrcSSE }, 886 { "insd", Op_insX },
965 { "movhps", Op_DstSrcSSE }, 887 { "insw", Op_insX },
966 { "movl", Op_DstSrc }, 888 { "int", Op_SrcImm },
967 { "movlhps", Op_DstSrcSSE }, 889 { "into", Op_0 },
968 { "movlpd", Op_DstSrcSSE }, 890 { "invd", Op_0 },
969 { "movlps", Op_DstSrcSSE }, 891 { "invlpg", Op_SrcMemNT },
970 { "movmskpd",Op_DstSrcSSE }, 892 { "iret", Op_iret },
971 { "movmskps",Op_DstSrcSSE }, 893 { "iretd", Op_iretd },
972 { "movntdq", Op_DstSrcNT }, // limited to sse, but mem dest 894 { "iretq", Op_iretd },
973 { "movnti", Op_DstSrcNT }, // limited to gpr, but mem dest 895 { "ja", Op_CBranch },
974 { "movntpd", Op_DstSrcNT }, // limited to sse, but mem dest 896 { "jae", Op_CBranch },
975 { "movntps", Op_DstSrcNT }, // limited to sse, but mem dest 897 { "jb", Op_CBranch },
976 { "movntq", Op_DstSrcNT }, // limited to mmx, but mem dest 898 { "jbe", Op_CBranch },
977 { "movq", Op_DstSrcNT }, // limited to sse and mmx 899 { "jc", Op_CBranch },
978 { "movq2dq", Op_DstSrcNT }, // limited to sse <- mmx regs 900 { "jcxz", Op_CBranch },
979 { "movs", Op_movs }, 901 { "je", Op_CBranch },
980 { "movsb", Op_movsX }, 902 { "jecxz", Op_CBranch },
981 { "movsd", Op_movsd }, 903 { "jg", Op_CBranch },
982 { "movsq", Op_movsd }, 904 { "jge", Op_CBranch },
983 { "movshdup", Op_DstSrcSSE }, 905 { "jl", Op_CBranch },
984 { "movsldup", Op_DstSrcSSE }, 906 { "jle", Op_CBranch },
985 { "movss", Op_DstSrcSSE }, 907 { "jmp", Op_Branch },
986 { "movsw", Op_movsX }, 908 { "jmpe", Op_Branch },
987 { "movsx", Op_movsx }, // word-only, reg dest 909 { "jmpf", Op_Branch },
988 { "movsxd", Op_movsx }, 910 { "jna", Op_CBranch },
989 { "movupd",Op_DstSrcSSE }, 911 { "jnae", Op_CBranch },
990 { "movups",Op_DstSrcSSE }, 912 { "jnb", Op_CBranch },
991 { "movzbl", Op_DstSrcNT }, 913 { "jnbe", Op_CBranch },
992 { "movzx", Op_movzx }, 914 { "jnc", Op_CBranch },
993 { "mul", Op_DstSrcNT }, 915 { "jne", Op_CBranch },
994 { "mulpd", Op_DstSrcSSE }, 916 { "jng", Op_CBranch },
995 { "mulps", Op_DstSrcSSE }, 917 { "jnge", Op_CBranch },
996 { "mulsd", Op_DstSrcSSE }, 918 { "jnl", Op_CBranch },
997 { "mulss", Op_DstSrcSSE }, 919 { "jnle", Op_CBranch },
998 { "mwait", Op_0 }, 920 { "jno", Op_CBranch },
999 { "naked", Op_Naked }, 921 { "jnp", Op_CBranch },
1000 { "neg", Op_UpdF }, 922 { "jns", Op_CBranch },
1001 { "nop", Op_0 }, 923 { "jnz", Op_CBranch },
1002 { "not", Op_Upd }, 924 { "jo", Op_CBranch },
1003 { "or", Op_UpdSrcF }, 925 { "jp", Op_CBranch },
1004 { "orpd", Op_DstSrcSSE }, 926 { "jpe", Op_CBranch },
1005 { "orps", Op_DstSrcSSE }, 927 { "jpo", Op_CBranch },
1006 { "out", Op_out }, 928 { "jrcxz", Op_CBranch },
1007 { "outs", Op_outs }, 929 { "js", Op_CBranch },
1008 { "outsb", Op_outsX }, 930 { "jz", Op_CBranch },
1009 { "outsd", Op_outsX }, 931 { "lahf", Op_0_AX },
1010 { "outsw", Op_outsX }, 932 { "lar", Op_DstSrcFW }, // reg dest only
1011 { "pabsb", Op_DstSrcSSE }, 933 { "lddqu", Op_DstSrcSSE },
1012 { "pabsw", Op_DstSrcSSE }, 934 { "ldmxcsr", Op_SrcMemNT },
1013 { "pabsq", Op_DstSrcSSE }, 935 { "lds", Op_DstSrc }, // reg dest only
1014 { "packssdw", Op_DstSrcMMX }, // %% also SSE 936 { "lea", Op_DstSrc }, // "
1015 { "packsswb", Op_DstSrcMMX }, 937 { "leaq", Op_DstSrcSSE }, // "
1016 { "packuswb", Op_DstSrcMMX }, 938 { "leave", Op_0 }, // EBP,ESP clobbers
1017 { "paddb", Op_DstSrcMMX }, 939 { "lfence",Op_0 },
1018 { "paddd", Op_DstSrcMMX }, 940 { "lfs", Op_DstSrc },
1019 { "paddq", Op_DstSrcMMX }, 941 { "lgdt", Op_SrcMemNT },
1020 { "paddsb", Op_DstSrcMMX }, 942 { "lgs", Op_DstSrc },
1021 { "paddsw", Op_DstSrcMMX }, 943 { "lidt", Op_SrcMemNT },
1022 { "paddusb", Op_DstSrcMMX }, 944 { "lldt", Op_SrcRMWNT },
1023 { "paddusw", Op_DstSrcMMX }, 945 { "lmsw", Op_SrcRMWNT },
1024 { "paddw", Op_DstSrcMMX }, 946 { "lock", Op_0 },
1025 { "palignr", Op_DstSrcSSE }, 947 { "lods", Op_lods },
1026 { "pand", Op_DstSrcMMX }, 948 { "lodsb", Op_lodsX },
1027 { "pandn", Op_DstSrcMMX }, 949 { "lodsd", Op_lodsX },
1028 { "pause", Op_DstSrcMMX }, 950 { "lodsw", Op_lodsX },
1029 { "pavgb", Op_DstSrcMMX }, 951 { "lodsq", Op_lodsX },
1030 { "pavgw", Op_DstSrcMMX }, 952 { "loop", Op_Loop },
1031 { "pcmpeqb", Op_DstSrcMMX }, 953 { "loope", Op_Loop },
1032 { "pcmpeqd", Op_DstSrcMMX }, 954 { "loopne",Op_Loop },
1033 { "pcmpeqw", Op_DstSrcMMX }, 955 { "loopnz",Op_Loop },
1034 { "pcmpgtb", Op_DstSrcMMX }, 956 { "loopz", Op_Loop },
1035 { "pcmpgtd", Op_DstSrcMMX }, 957 { "lsl", Op_DstSrcFW }, // reg dest only
1036 { "pcmpgtw", Op_DstSrcMMX }, 958 { "lss", Op_DstSrc },
1037 { "pextrw", Op_DstSrcImmM }, // gpr32 dest 959 { "ltr", Op_DstMemNT },
1038 { "phaddd", Op_DstSrcSSE }, 960 { "maskmovdqu", Op_SrcSrcMMX }, // writes to [edi]
1039 { "phaddsw", Op_DstSrcSSE }, 961 { "maskmovq", Op_SrcSrcMMX },
1040 { "phaddw", Op_DstSrcSSE }, 962 { "maxpd", Op_DstSrcSSE },
1041 { "phsubd", Op_DstSrcSSE }, 963 { "maxps", Op_DstSrcSSE },
1042 { "phsubsw", Op_DstSrcSSE }, 964 { "maxsd", Op_DstSrcSSE },
1043 { "phsubw", Op_DstSrcSSE }, 965 { "maxss", Op_DstSrcSSE },
1044 { "pinsrw", Op_DstSrcImmM }, // gpr32(16), mem16 src, sse too 966 { "mfence",Op_0},
1045 { "pmaddubsw", Op_DstSrcSSE }, 967 { "minpd", Op_DstSrcSSE },
1046 { "pmaddwd", Op_DstSrcMMX }, 968 { "minps", Op_DstSrcSSE },
1047 { "pmaxsw", Op_DstSrcMMX }, 969 { "minsd", Op_DstSrcSSE },
1048 { "pmaxub", Op_DstSrcMMX }, 970 { "minss", Op_DstSrcSSE },
1049 { "pminsw", Op_DstSrcMMX }, 971 { "monitor", Op_0 },
1050 { "pminub", Op_DstSrcMMX }, 972 { "mov", Op_DstSrc },
1051 { "pmovmskb", Op_DstSrcMMX }, 973 { "movapd", Op_DstSrcSSE },
1052 { "pmulhrsw", Op_DstSrcMMX }, 974 { "movaps", Op_DstSrcSSE },
1053 { "pmulhuw", Op_DstSrcMMX }, 975 { "movb", Op_DstSrcNT },
1054 { "pmulhw", Op_DstSrcMMX }, 976 { "movd", Op_DstSrcNT }, // also mmx and sse
1055 { "pmullw", Op_DstSrcMMX }, 977 { "movddup", Op_DstSrcSSE },
1056 { "pmuludq", Op_DstSrcMMX }, // also sse 978 { "movdq2q", Op_DstSrcNT }, // mmx/sse
1057 { "popf", Op_SizedStack }, // rewrite the insn with a special case 979 { "movdqa", Op_DstSrcSSE },
1058 { "popfq", Op_SizedStack }, 980 { "movdqu", Op_DstSrcSSE },
1059 { "popq", Op_push }, 981 { "movhlps", Op_DstSrcSSE },
1060 { "por", Op_DstSrcMMX }, 982 { "movhpd", Op_DstSrcSSE },
1061 { "prefetchnta", Op_SrcMemNT }, 983 { "movhps", Op_DstSrcSSE },
1062 { "prefetcht0", Op_SrcMemNT }, 984 { "movl", Op_DstSrc },
1063 { "prefetcht1", Op_SrcMemNT }, 985 { "movlhps", Op_DstSrcSSE },
1064 { "prefetcht2", Op_SrcMemNT }, 986 { "movlpd", Op_DstSrcSSE },
1065 { "psadbw", Op_DstSrcMMX }, 987 { "movlps", Op_DstSrcSSE },
1066 { "pshufb", Op_DstSrcImmM }, 988 { "movmskpd",Op_DstSrcSSE },
1067 { "pshufd", Op_DstSrcImmM }, 989 { "movmskps",Op_DstSrcSSE },
1068 { "pshufhw", Op_DstSrcImmM }, 990 { "movntdq", Op_DstSrcNT }, // limited to sse, but mem dest
1069 { "pshuflw", Op_DstSrcImmM }, 991 { "movnti", Op_DstSrcNT }, // limited to gpr, but mem dest
1070 { "pshufw", Op_DstSrcImmM }, 992 { "movntpd", Op_DstSrcNT }, // limited to sse, but mem dest
1071 { "psignb", Op_DstSrcSSE }, 993 { "movntps", Op_DstSrcNT }, // limited to sse, but mem dest
1072 { "psignd", Op_DstSrcSSE }, 994 { "movntq", Op_DstSrcNT }, // limited to mmx, but mem dest
1073 { "psignw", Op_DstSrcSSE }, 995 { "movq", Op_DstSrcNT }, // limited to sse and mmx
1074 { "pslld", Op_DstSrcMMX }, // immediate operands... 996 { "movq2dq", Op_DstSrcNT }, // limited to sse <- mmx regs
1075 { "pslldq", Op_DstSrcMMX }, 997 { "movs", Op_movs },
1076 { "psllq", Op_DstSrcMMX }, 998 { "movsb", Op_movsX },
1077 { "psllw", Op_DstSrcMMX }, 999 { "movsd", Op_movsd },
1078 { "psrad", Op_DstSrcMMX }, 1000 { "movsq", Op_movsd },
1079 { "psraw", Op_DstSrcMMX }, 1001 { "movshdup", Op_DstSrcSSE },
1080 { "psrld", Op_DstSrcMMX }, 1002 { "movsldup", Op_DstSrcSSE },
1081 { "psrldq", Op_DstSrcMMX }, 1003 { "movss", Op_DstSrcSSE },
1082 { "psrlq", Op_DstSrcMMX }, 1004 { "movsw", Op_movsX },
1083 { "psrlw", Op_DstSrcMMX }, 1005 { "movsx", Op_movsx }, // word-only, reg dest
1084 { "psubb", Op_DstSrcMMX }, 1006 { "movsxd", Op_movsx },
1085 { "psubd", Op_DstSrcMMX }, 1007 { "movupd",Op_DstSrcSSE },
1086 { "psubq", Op_DstSrcMMX }, 1008 { "movups",Op_DstSrcSSE },
1087 { "psubsb", Op_DstSrcMMX }, 1009 { "movzbl", Op_DstSrcNT },
1088 { "psubsw", Op_DstSrcMMX }, 1010 { "movzx", Op_movzx },
1089 { "psubusb", Op_DstSrcMMX }, 1011 { "mul", Op_DstSrcNT },
1090 { "psubusw", Op_DstSrcMMX }, 1012 { "mulpd", Op_DstSrcSSE },
1091 { "psubw", Op_DstSrcMMX }, 1013 { "mulps", Op_DstSrcSSE },
1092 { "punpckhbw", Op_DstSrcMMX }, 1014 { "mulsd", Op_DstSrcSSE },
1093 { "punpckhdq", Op_DstSrcMMX }, 1015 { "mulss", Op_DstSrcSSE },
1094 { "punpckhqdq",Op_DstSrcMMX }, 1016 { "mwait", Op_0 },
1095 { "punpckhwd", Op_DstSrcMMX }, 1017 { "naked", Op_Naked },
1096 { "punpcklbw", Op_DstSrcMMX }, 1018 { "neg", Op_UpdF },
1097 { "punpckldq", Op_DstSrcMMX }, 1019 { "nop", Op_0 },
1098 { "punpcklqdq",Op_DstSrcMMX }, 1020 { "not", Op_Upd },
1099 { "punpcklwd", Op_DstSrcMMX }, 1021 { "or", Op_UpdSrcF },
1100 { "pushf", Op_SizedStack }, 1022 { "orpd", Op_DstSrcSSE },
1101 { "pushfq", Op_SizedStack }, 1023 { "orps", Op_DstSrcSSE },
1102 { "pushq", Op_push }, 1024 { "out", Op_out },
1103 { "pxor", Op_DstSrcMMX }, 1025 { "outs", Op_outs },
1104 { "rcl", Op_Shift }, // limited src operands -- change to shift 1026 { "outsb", Op_outsX },
1105 { "rcpps", Op_DstSrcSSE }, 1027 { "outsd", Op_outsX },
1106 { "rcpss", Op_DstSrcSSE }, 1028 { "outsw", Op_outsX },
1107 { "rcr", Op_Shift }, 1029 { "pabsb", Op_DstSrcSSE },
1108 { "rdmsr", Op_0_DXAX }, 1030 { "pabsw", Op_DstSrcSSE },
1109 { "rdpmc", Op_0_DXAX }, 1031 { "pabsq", Op_DstSrcSSE },
1110 { "rdtsc", Op_0_DXAX }, 1032 { "packssdw", Op_DstSrcMMX }, // %% also SSE
1111 { "rep", Op_0 }, 1033 { "packsswb", Op_DstSrcMMX },
1112 { "repe", Op_0 }, 1034 { "packuswb", Op_DstSrcMMX },
1113 { "repne", Op_0 }, 1035 { "paddb", Op_DstSrcMMX },
1114 { "repnz", Op_0 }, 1036 { "paddd", Op_DstSrcMMX },
1115 { "repz", Op_0 }, 1037 { "paddq", Op_DstSrcMMX },
1116 { "ret", Op_ret }, 1038 { "paddsb", Op_DstSrcMMX },
1117 { "retf", Op_retf }, 1039 { "paddsw", Op_DstSrcMMX },
1118 { "retn", Op_retf }, 1040 { "paddusb", Op_DstSrcMMX },
1119 { "rol", Op_Shift }, 1041 { "paddusw", Op_DstSrcMMX },
1120 { "ror", Op_Shift }, 1042 { "paddw", Op_DstSrcMMX },
1121 { "rsm", Op_0 }, 1043 { "palignr", Op_DstSrcSSE },
1122 { "rsqrtps", Op_DstSrcSSE }, 1044 { "pand", Op_DstSrcMMX },
1123 { "rsqrtss", Op_DstSrcSSE }, 1045 { "pandn", Op_DstSrcMMX },
1124 { "sahf", Op_Flags }, 1046 { "pause", Op_DstSrcMMX },
1125 { "sal", Op_Shift }, 1047 { "pavgb", Op_DstSrcMMX },
1126 { "salq", Op_DstSrcNT }, 1048 { "pavgw", Op_DstSrcMMX },
1127 { "sar", Op_Shift }, 1049 { "pcmpeqb", Op_DstSrcMMX },
1128 { "sbb", Op_UpdSrcF }, 1050 { "pcmpeqd", Op_DstSrcMMX },
1129 { "scas", Op_scas }, 1051 { "pcmpeqw", Op_DstSrcMMX },
1130 { "scasb", Op_scasX }, 1052 { "pcmpgtb", Op_DstSrcMMX },
1131 { "scasd", Op_scasX }, 1053 { "pcmpgtd", Op_DstSrcMMX },
1132 { "scasw", Op_scasX }, 1054 { "pcmpgtw", Op_DstSrcMMX },
1133 { "scasq", Op_scasX }, 1055 { "pextrw", Op_DstSrcImmM }, // gpr32 dest
1134 { "seta", Op_DstRMBNT }, // also gpr8 1056 { "phaddd", Op_DstSrcSSE },
1135 { "setae", Op_DstRMBNT }, 1057 { "phaddsw", Op_DstSrcSSE },
1136 { "setb", Op_DstRMBNT }, 1058 { "phaddw", Op_DstSrcSSE },
1137 { "setbe", Op_DstRMBNT }, 1059 { "phsubd", Op_DstSrcSSE },
1138 { "setc", Op_DstRMBNT }, 1060 { "phsubsw", Op_DstSrcSSE },
1139 { "sete", Op_DstRMBNT }, 1061 { "phsubw", Op_DstSrcSSE },
1140 { "setg", Op_DstRMBNT }, 1062 { "pinsrw", Op_DstSrcImmM }, // gpr32(16), mem16 src, sse too
1141 { "setge", Op_DstRMBNT }, 1063 { "pmaddubsw", Op_DstSrcSSE },
1142 { "setl", Op_DstRMBNT }, 1064 { "pmaddwd", Op_DstSrcMMX },
1143 { "setle", Op_DstRMBNT }, 1065 { "pmaxsw", Op_DstSrcMMX },
1144 { "setna", Op_DstRMBNT }, 1066 { "pmaxub", Op_DstSrcMMX },
1145 { "setnae", Op_DstRMBNT }, 1067 { "pminsw", Op_DstSrcMMX },
1146 { "setnb", Op_DstRMBNT }, 1068 { "pminub", Op_DstSrcMMX },
1147 { "setnbe", Op_DstRMBNT }, 1069 { "pmovmskb", Op_DstSrcMMX },
1148 { "setnc", Op_DstRMBNT }, 1070 { "pmulhrsw", Op_DstSrcMMX },
1149 { "setne", Op_DstRMBNT }, 1071 { "pmulhuw", Op_DstSrcMMX },
1150 { "setng", Op_DstRMBNT }, 1072 { "pmulhw", Op_DstSrcMMX },
1151 { "setnge", Op_DstRMBNT }, 1073 { "pmullw", Op_DstSrcMMX },
1152 { "setnl", Op_DstRMBNT }, 1074 { "pmuludq", Op_DstSrcMMX }, // also sse
1153 { "setnle", Op_DstRMBNT }, 1075 { "popf", Op_SizedStack }, // rewrite the insn with a special case
1154 { "setno", Op_DstRMBNT }, 1076 { "popfq", Op_SizedStack },
1155 { "setnp", Op_DstRMBNT }, 1077 { "popq", Op_push },
1156 { "setns", Op_DstRMBNT }, 1078 { "por", Op_DstSrcMMX },
1157 { "setnz", Op_DstRMBNT }, 1079 { "prefetchnta", Op_SrcMemNT },
1158 { "seto", Op_DstRMBNT }, 1080 { "prefetcht0", Op_SrcMemNT },
1159 { "setp", Op_DstRMBNT }, 1081 { "prefetcht1", Op_SrcMemNT },
1160 { "setpe", Op_DstRMBNT }, 1082 { "prefetcht2", Op_SrcMemNT },
1161 { "setpo", Op_DstRMBNT }, 1083 { "psadbw", Op_DstSrcMMX },
1162 { "sets", Op_DstRMBNT }, 1084 { "pshufb", Op_DstSrcImmM },
1163 { "setz", Op_DstRMBNT }, 1085 { "pshufd", Op_DstSrcImmM },
1164 { "sfence", Op_0 }, 1086 { "pshufhw", Op_DstSrcImmM },
1165 { "sgdt", Op_DstMemNT }, 1087 { "pshuflw", Op_DstSrcImmM },
1166 { "shl", Op_Shift }, 1088 { "pshufw", Op_DstSrcImmM },
1167 { "shld", Op_UpdSrcShft }, 1089 { "psignb", Op_DstSrcSSE },
1168 { "shr", Op_Shift }, 1090 { "psignd", Op_DstSrcSSE },
1169 { "shrd", Op_UpdSrcShft }, 1091 { "psignw", Op_DstSrcSSE },
1170 { "shufpd", Op_DstSrcImmS }, 1092 { "pslld", Op_DstSrcMMX }, // immediate operands...
1171 { "shufps", Op_DstSrcImmS }, 1093 { "pslldq", Op_DstSrcMMX },
1172 { "sidt", Op_DstMemNT }, 1094 { "psllq", Op_DstSrcMMX },
1173 { "sldt", Op_DstRMWNT }, 1095 { "psllw", Op_DstSrcMMX },
1174 { "smsw", Op_DstRMWNT }, 1096 { "psrad", Op_DstSrcMMX },
1175 { "sqrtpd", Op_DstSrcSSE }, 1097 { "psraw", Op_DstSrcMMX },
1176 { "sqrtps", Op_DstSrcSSE }, 1098 { "psrld", Op_DstSrcMMX },
1177 { "sqrtsd", Op_DstSrcSSE }, 1099 { "psrldq", Op_DstSrcMMX },
1178 { "sqrtss", Op_DstSrcSSE }, 1100 { "psrlq", Op_DstSrcMMX },
1179 { "stc", Op_Flags }, 1101 { "psrlw", Op_DstSrcMMX },
1180 { "std", Op_Flags }, 1102 { "psubb", Op_DstSrcMMX },
1181 { "sti", Op_Flags }, 1103 { "psubd", Op_DstSrcMMX },
1182 { "stmxcsr",Op_DstMemNT }, 1104 { "psubq", Op_DstSrcMMX },
1183 { "stos", Op_stos }, 1105 { "psubsb", Op_DstSrcMMX },
1184 { "stosb", Op_stosX }, 1106 { "psubsw", Op_DstSrcMMX },
1185 { "stosd", Op_stosX }, 1107 { "psubusb", Op_DstSrcMMX },
1186 { "stosw", Op_stosX }, 1108 { "psubusw", Op_DstSrcMMX },
1187 { "stosq", Op_stosX }, 1109 { "psubw", Op_DstSrcMMX },
1188 { "str", Op_DstMemNT }, // also r16 1110 { "punpckhbw", Op_DstSrcMMX },
1189 { "sub", Op_UpdSrcF }, 1111 { "punpckhdq", Op_DstSrcMMX },
1190 { "subpd", Op_DstSrcSSE }, 1112 { "punpckhqdq",Op_DstSrcMMX },
1191 { "subps", Op_DstSrcSSE }, 1113 { "punpckhwd", Op_DstSrcMMX },
1192 { "subq", Op_DstSrcSSE }, 1114 { "punpcklbw", Op_DstSrcMMX },
1193 { "subsd", Op_DstSrcSSE }, 1115 { "punpckldq", Op_DstSrcMMX },
1194 { "subss", Op_DstSrcSSE }, 1116 { "punpcklqdq",Op_DstSrcMMX },
1195 { "swapgs", Op_DstSrcSSE }, 1117 { "punpcklwd", Op_DstSrcMMX },
1196 { "sysenter",Op_0 }, 1118 { "pushf", Op_SizedStack },
1197 { "sysexit", Op_0 }, 1119 { "pushfq", Op_SizedStack },
1198 { "sysret", Op_0 }, 1120 { "pushq", Op_push },
1199 { "testl", Op_DstSrcNT }, 1121 { "pxor", Op_DstSrcMMX },
1200 { "ucomisd", Op_SrcSrcSSEF }, 1122 { "rcl", Op_Shift }, // limited src operands -- change to shift
1201 { "ucomiss", Op_SrcSrcSSEF }, 1123 { "rcpps", Op_DstSrcSSE },
1202 { "ud2", Op_0 }, 1124 { "rcpss", Op_DstSrcSSE },
1203 { "unpckhpd", Op_DstSrcSSE }, 1125 { "rcr", Op_Shift },
1204 { "unpckhps", Op_DstSrcSSE }, 1126 { "rdmsr", Op_0_DXAX },
1205 { "unpcklpd", Op_DstSrcSSE }, 1127 { "rdpmc", Op_0_DXAX },
1206 { "unpcklps", Op_DstSrcSSE }, 1128 { "rdtsc", Op_0_DXAX },
1207 { "verr", Op_SrcMemNTF }, 1129 { "rep", Op_0 },
1208 { "verw", Op_SrcMemNTF }, 1130 { "repe", Op_0 },
1209 { "wbinvd", Op_0 }, 1131 { "repne", Op_0 },
1210 { "wrmsr", Op_0 }, 1132 { "repnz", Op_0 },
1211 { "xadd", Op_UpdUpdF }, 1133 { "repz", Op_0 },
1212 { "xchg", Op_UpdUpd }, 1134 { "ret", Op_ret },
1213 { "xlat", Op_xlat }, 1135 { "retf", Op_retf },
1214 { "xlatb", Op_0_AX }, 1136 { "retn", Op_retf },
1215 { "xor", Op_DstSrcF }, 1137 { "rol", Op_Shift },
1216 { "xorpd", Op_DstSrcSSE }, 1138 { "ror", Op_Shift },
1217 { "xorps", Op_DstSrcSSE }, 1139 { "rsm", Op_0 },
1218 { "xorq", Op_DstSrcNT }, 1140 { "rsqrtps", Op_DstSrcSSE },
1219 }; 1141 { "rsqrtss", Op_DstSrcSSE },
1220 1142 { "sahf", Op_Flags },
1221 typedef enum { 1143 { "sal", Op_Shift },
1222 Default_Ptr = 0, 1144 { "salq", Op_DstSrcNT },
1223 Byte_Ptr = 1, 1145 { "sar", Op_Shift },
1224 Short_Ptr = 2, 1146 { "sbb", Op_UpdSrcF },
1225 Int_Ptr = 4, 1147 { "scas", Op_scas },
1226 QWord_Ptr = 8, 1148 { "scasb", Op_scasX },
1227 Float_Ptr = 4, 1149 { "scasd", Op_scasX },
1228 Double_Ptr = 8, 1150 { "scasw", Op_scasX },
1229 Extended_Ptr = 10, 1151 { "scasq", Op_scasX },
1230 Near_Ptr = 98, 1152 { "seta", Op_DstRMBNT }, // also gpr8
1231 Far_Ptr = 99, 1153 { "setae", Op_DstRMBNT },
1232 N_PtrTypes 1154 { "setb", Op_DstRMBNT },
1233 } PtrType; 1155 { "setbe", Op_DstRMBNT },
1234 1156 { "setc", Op_DstRMBNT },
1235 static const int N_PtrNames = 8; 1157 { "sete", Op_DstRMBNT },
1236 static const char * ptrTypeNameTable[N_PtrNames] = { 1158 { "setg", Op_DstRMBNT },
1237 "word", "dword", "qword", 1159 { "setge", Op_DstRMBNT },
1238 "float", "double", "extended", 1160 { "setl", Op_DstRMBNT },
1239 "near", "far" 1161 { "setle", Op_DstRMBNT },
1240 }; 1162 { "setna", Op_DstRMBNT },
1241 1163 { "setnae", Op_DstRMBNT },
1242 static Identifier * ptrTypeIdentTable[N_PtrNames]; 1164 { "setnb", Op_DstRMBNT },
1243 static PtrType ptrTypeValueTable[N_PtrNames] = { 1165 { "setnbe", Op_DstRMBNT },
1244 Short_Ptr, Int_Ptr, QWord_Ptr, 1166 { "setnc", Op_DstRMBNT },
1245 Float_Ptr, Double_Ptr, Extended_Ptr, 1167 { "setne", Op_DstRMBNT },
1246 Near_Ptr, Far_Ptr 1168 { "setng", Op_DstRMBNT },
1247 }; 1169 { "setnge", Op_DstRMBNT },
1248 1170 { "setnl", Op_DstRMBNT },
1249 typedef enum { 1171 { "setnle", Op_DstRMBNT },
1250 Opr_Invalid, 1172 { "setno", Op_DstRMBNT },
1251 Opr_Immediate, 1173 { "setnp", Op_DstRMBNT },
1252 Opr_Reg, 1174 { "setns", Op_DstRMBNT },
1253 Opr_Mem 1175 { "setnz", Op_DstRMBNT },
1254 } OperandClass; 1176 { "seto", Op_DstRMBNT },
1255 1177 { "setp", Op_DstRMBNT },
1256 /* kill inlining if we reference a local? */ 1178 { "setpe", Op_DstRMBNT },
1257 1179 { "setpo", Op_DstRMBNT },
1258 /* DMD seems to allow only one 'symbol' per operand .. include __LOCAL_SIZE */ 1180 { "sets", Op_DstRMBNT },
1259 1181 { "setz", Op_DstRMBNT },
1260 /* DMD offset usage: <parm>[<reg>] seems to always be relative to EBP+8 .. even 1182 { "sfence", Op_0 },
1261 if naked.. */ 1183 { "sgdt", Op_DstMemNT },
1184 { "shl", Op_Shift },
1185 { "shld", Op_UpdSrcShft },
1186 { "shr", Op_Shift },
1187 { "shrd", Op_UpdSrcShft },
1188 { "shufpd", Op_DstSrcImmS },
1189 { "shufps", Op_DstSrcImmS },
1190 { "sidt", Op_DstMemNT },
1191 { "sldt", Op_DstRMWNT },
1192 { "smsw", Op_DstRMWNT },
1193 { "sqrtpd", Op_DstSrcSSE },
1194 { "sqrtps", Op_DstSrcSSE },
1195 { "sqrtsd", Op_DstSrcSSE },
1196 { "sqrtss", Op_DstSrcSSE },
1197 { "stc", Op_Flags },
1198 { "std", Op_Flags },
1199 { "sti", Op_Flags },
1200 { "stmxcsr",Op_DstMemNT },
1201 { "stos", Op_stos },
1202 { "stosb", Op_stosX },
1203 { "stosd", Op_stosX },
1204 { "stosw", Op_stosX },
1205 { "stosq", Op_stosX },
1206 { "str", Op_DstMemNT }, // also r16
1207 { "sub", Op_UpdSrcF },
1208 { "subpd", Op_DstSrcSSE },
1209 { "subps", Op_DstSrcSSE },
1210 { "subq", Op_DstSrcSSE },
1211 { "subsd", Op_DstSrcSSE },
1212 { "subss", Op_DstSrcSSE },
1213 { "swapgs", Op_DstSrcSSE },
1214 { "sysenter",Op_0 },
1215 { "sysexit", Op_0 },
1216 { "sysret", Op_0 },
1217 { "testl", Op_DstSrcNT },
1218 { "ucomisd", Op_SrcSrcSSEF },
1219 { "ucomiss", Op_SrcSrcSSEF },
1220 { "ud2", Op_0 },
1221 { "unpckhpd", Op_DstSrcSSE },
1222 { "unpckhps", Op_DstSrcSSE },
1223 { "unpcklpd", Op_DstSrcSSE },
1224 { "unpcklps", Op_DstSrcSSE },
1225 { "verr", Op_SrcMemNTF },
1226 { "verw", Op_SrcMemNTF },
1227 { "wbinvd", Op_0 },
1228 { "wrmsr", Op_0 },
1229 { "xadd", Op_UpdUpdF },
1230 { "xchg", Op_UpdUpd },
1231 { "xlat", Op_xlat },
1232 { "xlatb", Op_0_AX },
1233 { "xor", Op_DstSrcF },
1234 { "xorpd", Op_DstSrcSSE },
1235 { "xorps", Op_DstSrcSSE },
1236 { "xorq", Op_DstSrcNT },
1237 };
1238
1239 typedef enum
1240 {
1241 Default_Ptr = 0,
1242 Byte_Ptr = 1,
1243 Short_Ptr = 2,
1244 Int_Ptr = 4,
1245 QWord_Ptr = 8,
1246 Float_Ptr = 4,
1247 Double_Ptr = 8,
1248 Extended_Ptr = 10,
1249 Near_Ptr = 98,
1250 Far_Ptr = 99,
1251 N_PtrTypes
1252 } PtrType;
1253
1254 static const int N_PtrNames = 8;
1255 static const char * ptrTypeNameTable[N_PtrNames] =
1256 {
1257 "word", "dword", "qword",
1258 "float", "double", "extended",
1259 "near", "far"
1260 };
1261
1262 static Identifier * ptrTypeIdentTable[N_PtrNames];
1263 static PtrType ptrTypeValueTable[N_PtrNames] =
1264 {
1265 Short_Ptr, Int_Ptr, QWord_Ptr,
1266 Float_Ptr, Double_Ptr, Extended_Ptr,
1267 Near_Ptr, Far_Ptr
1268 };
1269
1270 typedef enum
1271 {
1272 Opr_Invalid,
1273 Opr_Immediate,
1274 Opr_Reg,
1275 Opr_Mem
1276 } OperandClass;
1277
1278 /* kill inlining if we reference a local? */
1279
1280 /* DMD seems to allow only one 'symbol' per operand .. include __LOCAL_SIZE */
1281
1282 /* DMD offset usage: <parm>[<reg>] seems to always be relative to EBP+8 .. even
1283 if naked.. */
1262 1284
1263 // mov eax, 4 1285 // mov eax, 4
1264 // mov eax, fs:4 1286 // mov eax, fs:4
1265 // -- have to assume we know whether or not to use '$' 1287 // -- have to assume we know whether or not to use '$'
1266 1288
1267 static Token eof_tok; 1289 static Token eof_tok;
1268 static Expression * Handled; 1290 static Expression * Handled;
1269 static Identifier * ident_seg; 1291 static Identifier * ident_seg;
1270 1292
1271 struct AsmProcessor 1293 struct AsmProcessor
1272 {
1273 typedef struct {
1274 int inBracket;
1275 int hasBracket;
1276 int hasNumber;
1277 int isOffset;
1278
1279 Reg segmentPrefix;
1280 Reg reg;
1281 sinteger_t constDisplacement; // use to build up.. should be int constant in the end..
1282 Array symbolDisplacement; // array of expressions or..
1283 Reg baseReg;
1284 Reg indexReg;
1285 int scale;
1286
1287 OperandClass cls;
1288 PtrType dataSize;
1289 PtrType dataSizeHint; // DMD can use the type of a referenced variable
1290 } Operand;
1291
1292 static const unsigned Max_Operands = 3;
1293
1294 AsmStatement * stmt;
1295 Scope * sc;
1296
1297 Token * token;
1298 OutBuffer * insnTemplate;
1299
1300 AsmOp op;
1301 AsmOpInfo * opInfo;
1302 Operand operands[Max_Operands];
1303 Identifier * opIdent;
1304 Operand * operand;
1305
1306 AsmProcessor(Scope * sc, AsmStatement * stmt)
1307 { 1294 {
1308 this->sc = sc; 1295 typedef struct
1309 this->stmt = stmt; 1296 {
1310 token = stmt->tokens; 1297 int inBracket;
1311 insnTemplate = new OutBuffer; 1298 int hasBracket;
1312 1299 int hasNumber;
1313 opInfo = NULL; 1300 int isOffset;
1314 1301
1315 if ( ! regInfo[0].ident ) { 1302 Reg segmentPrefix;
1316 char buf[8], *p; 1303 Reg reg;
1317 1304 sinteger_t constDisplacement; // use to build up.. should be int constant in the end..
1318 for (int i = 0; i < N_Regs; i++) { 1305 Array symbolDisplacement; // array of expressions or..
1319 strncpy(buf, regInfo[i].name, sizeof(buf) - 1); 1306 Reg baseReg;
1320 for (p = buf; *p; p++) 1307 Reg indexReg;
1321 *p = std::tolower(*p); 1308 int scale;
1322 regInfo[i].gccName = std::string(buf, p - buf); 1309
1323 if ( (i <= Reg_ST || i > Reg_ST7) && i != Reg_EFLAGS ) 1310 OperandClass cls;
1324 regInfo[i].ident = Lexer::idPool(regInfo[i].name); 1311 PtrType dataSize;
1325 } 1312 PtrType dataSizeHint; // DMD can use the type of a referenced variable
1326 1313 } Operand;
1327 for (int i = 0; i < N_PtrNames; i++) 1314
1328 ptrTypeIdentTable[i] = Lexer::idPool(ptrTypeNameTable[i]); 1315 static const unsigned Max_Operands = 3;
1329 1316
1330 Handled = new Expression(0, TOKvoid, sizeof(Expression)); 1317 AsmStatement * stmt;
1331 1318 Scope * sc;
1332 ident_seg = Lexer::idPool("seg"); 1319
1333 1320 Token * token;
1334 eof_tok.value = TOKeof; 1321 OutBuffer * insnTemplate;
1335 eof_tok.next = 0; 1322
1336 } 1323 AsmOp op;
1337 } 1324 AsmOpInfo * opInfo;
1338 1325 Operand operands[Max_Operands];
1339 void run() 1326 Identifier * opIdent;
1340 { 1327 Operand * operand;
1341 parse(); 1328
1342 } 1329 AsmProcessor ( Scope * sc, AsmStatement * stmt )
1343 1330 {
1344 void nextToken() { 1331 this->sc = sc;
1345 if (token->next) 1332 this->stmt = stmt;
1346 token = token->next; 1333 token = stmt->tokens;
1347 else 1334 insnTemplate = new OutBuffer;
1348 token = & eof_tok; 1335
1349 } 1336 opInfo = NULL;
1350 1337
1351 Token * peekToken() { 1338 if ( ! regInfo[0].ident )
1352 if (token->next) 1339 {
1353 return token->next; 1340 char buf[8], *p;
1354 else 1341
1355 return & eof_tok; 1342 for ( int i = 0; i < N_Regs; i++ )
1356 } 1343 {
1357 1344 strncpy ( buf, regInfo[i].name, sizeof ( buf ) - 1 );
1358 void expectEnd() { 1345 for ( p = buf; *p; p++ )
1359 if (token->value != TOKeof) 1346 *p = std::tolower ( *p );
1360 stmt->error("expected end of statement"); // %% extra at end... 1347 regInfo[i].gccName = std::string ( buf, p - buf );
1361 } 1348 if ( ( i <= Reg_ST || i > Reg_ST7 ) && i != Reg_EFLAGS )
1362 1349 regInfo[i].ident = Lexer::idPool ( regInfo[i].name );
1363 void parse() { 1350 }
1364 op = parseOpcode(); 1351
1365 1352 for ( int i = 0; i < N_PtrNames; i++ )
1366 switch (op) { 1353 ptrTypeIdentTable[i] = Lexer::idPool ( ptrTypeNameTable[i] );
1367 case Op_Align: 1354
1368 doAlign(); 1355 Handled = new Expression ( 0, TOKvoid, sizeof ( Expression ) );
1369 expectEnd(); 1356
1370 break; 1357 ident_seg = Lexer::idPool ( "seg" );
1371 case Op_Even: 1358
1372 doEven(); 1359 eof_tok.value = TOKeof;
1373 expectEnd(); 1360 eof_tok.next = 0;
1374 break; 1361 }
1375 case Op_Naked: 1362 }
1376 doNaked(); 1363
1377 expectEnd(); 1364 void run()
1378 break; 1365 {
1379 case Op_Invalid: 1366 parse();
1380 break; 1367 }
1381 default: 1368
1382 if (op >= Op_db && op <= Op_de) 1369 void nextToken()
1383 doData(); 1370 {
1384 else 1371 if ( token->next )
1385 doInstruction(); 1372 token = token->next;
1386 } 1373 else
1387 } 1374 token = & eof_tok;
1388 1375 }
1389 AsmOp parseOpcode() { 1376
1390 static const int N_ents = sizeof(opData)/sizeof(AsmOpEnt); 1377 Token * peekToken()
1391 1378 {
1392 switch (token->value) { 1379 if ( token->next )
1393 case TOKalign: 1380 return token->next;
1394 nextToken(); 1381 else
1395 return Op_Align; 1382 return & eof_tok;
1396 case TOKin: 1383 }
1397 nextToken(); 1384
1398 opIdent = Id::___in; 1385 void expectEnd()
1399 return Op_in; 1386 {
1400 case TOKint32: // "int" 1387 if ( token->value != TOKeof )
1388 stmt->error ( "expected end of statement" ); // %% extra at end...
1389 }
1390
1391 void parse()
1392 {
1393 op = parseOpcode();
1394
1395 switch ( op )
1396 {
1397 case Op_Align:
1398 doAlign();
1399 expectEnd();
1400 break;
1401 case Op_Even:
1402 doEven();
1403 expectEnd();
1404 break;
1405 case Op_Naked:
1406 doNaked();
1407 expectEnd();
1408 break;
1409 case Op_Invalid:
1410 break;
1411 default:
1412 if ( op >= Op_db && op <= Op_de )
1413 doData();
1414 else
1415 doInstruction();
1416 }
1417 }
1418
1419 AsmOp parseOpcode()
1420 {
1421 static const int N_ents = sizeof ( opData ) /sizeof ( AsmOpEnt );
1422
1423 switch ( token->value )
1424 {
1425 case TOKalign:
1426 nextToken();
1427 return Op_Align;
1428 case TOKin:
1429 nextToken();
1430 opIdent = Id::___in;
1431 return Op_in;
1432 case TOKint32: // "int"
1433 nextToken();
1434 opIdent = Id::__int;
1435 return Op_SrcImm;
1436 case TOKout:
1437 nextToken();
1438 opIdent = Id::___out;
1439 return Op_out;
1440 case TOKidentifier:
1441 // search for mnemonic below
1442 break;
1443 default:
1444 stmt->error ( "expected opcode" );
1445 return Op_Invalid;
1446 }
1447
1448 opIdent = token->ident;
1449 const char * opcode = token->ident->string;
1450
1401 nextToken(); 1451 nextToken();
1402 opIdent = Id::__int; 1452
1403 return Op_SrcImm; 1453 // %% okay to use bsearch?
1404 case TOKout: 1454 int i = 0, j = N_ents, k, l;
1405 nextToken(); 1455 do
1406 opIdent = Id::___out; 1456 {
1407 return Op_out; 1457 k = ( i + j ) / 2;
1408 case TOKidentifier: 1458 l = strcmp ( opcode, opData[k].inMnemonic );
1409 // search for mnemonic below 1459 if ( ! l )
1410 break; 1460 return opData[k].asmOp;
1411 default: 1461 else if ( l < 0 )
1412 stmt->error("expected opcode"); 1462 j = k;
1413 return Op_Invalid;
1414 }
1415
1416 opIdent = token->ident;
1417 const char * opcode = token->ident->string;
1418
1419 nextToken();
1420
1421 // %% okay to use bsearch?
1422 int i = 0, j = N_ents, k, l;
1423 do {
1424 k = (i + j) / 2;
1425 l = strcmp(opcode, opData[k].inMnemonic);
1426 if (! l)
1427 return opData[k].asmOp;
1428 else if (l < 0)
1429 j = k;
1430 else
1431 i = k + 1;
1432 } while (i != j);
1433
1434 stmt->error("unknown opcode '%s'", opcode);
1435
1436 return Op_Invalid;
1437 }
1438
1439 // need clobber information.. use information is good too...
1440 void doInstruction() {
1441 bool ok = true;
1442 unsigned operand_i = 0;
1443
1444 opInfo = & asmOpInfo[op];
1445 memset(operands, 0, sizeof(operands));
1446
1447 while (token->value != TOKeof) {
1448 if (operand_i < Max_Operands) {
1449 operand = & operands[operand_i];
1450 operand->reg = operand->baseReg = operand->indexReg =
1451 operand->segmentPrefix = Reg_Invalid;
1452 parseOperand();
1453 operand_i++;
1454 } else {
1455 ok = false;
1456 stmt->error("too many operands for instruction");
1457 break;
1458 }
1459
1460 if (token->value == TOKcomma)
1461 nextToken();
1462 else if (token->value != TOKeof) {
1463 ok = false;
1464 stmt->error("expected comma after operand");
1465 return;
1466 }
1467 }
1468 // if (operand_i < opInfo->minOperands) {
1469 // ok = false;
1470 // stmt->error("too few operands for instruction");
1471 // }
1472
1473 if ( matchOperands(operand_i) ) {
1474 AsmCode * asmcode = new AsmCode(N_Regs);
1475
1476 if (formatInstruction(operand_i, asmcode))
1477 stmt->asmcode = (code *) asmcode;
1478 }
1479 }
1480
1481 void setAsmCode() {
1482 AsmCode * asmcode = new AsmCode(N_Regs);
1483 asmcode->insnTemplateLen = insnTemplate->offset;
1484 asmcode->insnTemplate = (char*) insnTemplate->extractData();
1485 stmt->asmcode = (code*) asmcode;
1486 }
1487
1488 // note: doesn't update AsmOp op
1489 bool matchOperands(unsigned nOperands) {
1490 bool wrong_number = true;
1491
1492 for (unsigned i = 0; i < nOperands; i++)
1493 classifyOperand(& operands[i]);
1494
1495 while (1) {
1496 if (nOperands == opInfo->nOperands()) {
1497 wrong_number = false;
1498 /* Cases in which number of operands is not
1499 enough for a match: Op_FCmp/Op_FCmp1,
1500 Op_FCmpP/Op_FCmpP1 */
1501 for (unsigned i = 0; i < nOperands; i++) {
1502 Operand * operand = & operands[i];
1503
1504 switch (opInfo->operands[i] & Opr_ClassMask) {
1505 case OprC_Mem: // no FPMem currently
1506 if (operand->cls != Opr_Mem)
1507 goto no_match;
1508 break;
1509 case OprC_RFP:
1510 if (! (operand->reg >= Reg_ST && operand->reg <= Reg_ST7))
1511 goto no_match;
1512 break;
1513 default:
1514 break;
1515 }
1516 }
1517
1518 return true;
1519 }
1520 no_match:
1521 if (opInfo->linkType == Next_Form)
1522 opInfo = & asmOpInfo[ op = (AsmOp) opInfo->link ];
1523 else
1524 break;
1525 }
1526 if (wrong_number)
1527 stmt->error("wrong number of operands");
1528 else
1529 stmt->error("wrong operand types");
1530 return false;
1531 }
1532
1533 void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
1534 if (sc->func->naked)
1535 {
1536 switch(type)
1537 {
1538 case Arg_Integer:
1539 if (e->type->isunsigned())
1540 insnTemplate->printf("$%llu", e->toUInteger());
1541 else 1463 else
1542 insnTemplate->printf("$%lld", e->toInteger()); 1464 i = k + 1;
1543 break; 1465 }
1544 1466 while ( i != j );
1545 case Arg_Pointer: 1467
1546 stmt->error("unsupported pointer reference to '%s' in naked asm", e->toChars()); 1468 stmt->error ( "unknown opcode '%s'", opcode );
1547 break; 1469
1548 1470 return Op_Invalid;
1549 case Arg_Memory: 1471 }
1550 if (e->op == TOKvar) 1472
1551 { 1473 // need clobber information.. use information is good too...
1552 VarExp* v = (VarExp*)e; 1474 void doInstruction()
1553 if (VarDeclaration* vd = v->var->isVarDeclaration()) 1475 {
1476 bool ok = true;
1477 unsigned operand_i = 0;
1478
1479 opInfo = & asmOpInfo[op];
1480 memset ( operands, 0, sizeof ( operands ) );
1481
1482 while ( token->value != TOKeof )
1483 {
1484 if ( operand_i < Max_Operands )
1485 {
1486 operand = & operands[operand_i];
1487 operand->reg = operand->baseReg = operand->indexReg =
1488 operand->segmentPrefix = Reg_Invalid;
1489 parseOperand();
1490 operand_i++;
1491 }
1492 else
1493 {
1494 ok = false;
1495 stmt->error ( "too many operands for instruction" );
1496 break;
1497 }
1498
1499 if ( token->value == TOKcomma )
1500 nextToken();
1501 else if ( token->value != TOKeof )
1502 {
1503 ok = false;
1504 stmt->error ( "expected comma after operand" );
1505 return;
1506 }
1507 }
1508 // if (operand_i < opInfo->minOperands) {
1509 // ok = false;
1510 // stmt->error("too few operands for instruction");
1511 // }
1512
1513 if ( matchOperands ( operand_i ) )
1514 {
1515 AsmCode * asmcode = new AsmCode ( N_Regs );
1516
1517 if ( formatInstruction ( operand_i, asmcode ) )
1518 stmt->asmcode = ( code * ) asmcode;
1519 }
1520 }
1521
1522 void setAsmCode()
1523 {
1524 AsmCode * asmcode = new AsmCode ( N_Regs );
1525 asmcode->insnTemplateLen = insnTemplate->offset;
1526 asmcode->insnTemplate = ( char* ) insnTemplate->extractData();
1527 stmt->asmcode = ( code* ) asmcode;
1528 }
1529
1530 // note: doesn't update AsmOp op
1531 bool matchOperands ( unsigned nOperands )
1532 {
1533 bool wrong_number = true;
1534
1535 for ( unsigned i = 0; i < nOperands; i++ )
1536 classifyOperand ( & operands[i] );
1537
1538 while ( 1 )
1539 {
1540 if ( nOperands == opInfo->nOperands() )
1541 {
1542 wrong_number = false;
1543 /* Cases in which number of operands is not
1544 enough for a match: Op_FCmp/Op_FCmp1,
1545 Op_FCmpP/Op_FCmpP1 */
1546 for ( unsigned i = 0; i < nOperands; i++ )
1554 { 1547 {
1555 if (!vd->isDataseg()) 1548 Operand * operand = & operands[i];
1549
1550 switch ( opInfo->operands[i] & Opr_ClassMask )
1556 { 1551 {
1557 stmt->error("only global variables can be referenced by identifier in naked asm"); 1552 case OprC_Mem: // no FPMem currently
1558 break; 1553 if ( operand->cls != Opr_Mem )
1554 goto no_match;
1555 break;
1556 case OprC_RFP:
1557 if ( ! ( operand->reg >= Reg_ST && operand->reg <= Reg_ST7 ) )
1558 goto no_match;
1559 break;
1560 default:
1561 break;
1559 } 1562 }
1560 1563 }
1561 // osx needs an extra underscore 1564
1562 if (global.params.os == OSMacOSX) 1565 return true;
1563 insnTemplate->writestring("_"); 1566 }
1564 1567 no_match:
1565 // print out the mangle 1568 if ( opInfo->linkType == Next_Form )
1566 insnTemplate->writestring(vd->mangle()); 1569 opInfo = & asmOpInfo[ op = ( AsmOp ) opInfo->link ];
1567 vd->nakedUse = true; 1570 else
1571 break;
1572 }
1573 if ( wrong_number )
1574 stmt->error ( "wrong number of operands" );
1575 else
1576 stmt->error ( "wrong operand types" );
1577 return false;
1578 }
1579
1580 void addOperand ( const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input )
1581 {
1582 if ( sc->func->naked )
1583 {
1584 switch ( type )
1585 {
1586 case Arg_Integer:
1587 if ( e->type->isunsigned() )
1588 insnTemplate->printf ( "$%llu", e->toUInteger() );
1589 else
1590 insnTemplate->printf ( "$%lld", e->toInteger() );
1591 break;
1592
1593 case Arg_Pointer:
1594 stmt->error ( "unsupported pointer reference to '%s' in naked asm", e->toChars() );
1595 break;
1596
1597 case Arg_Memory:
1598 if ( e->op == TOKvar )
1599 {
1600 VarExp* v = ( VarExp* ) e;
1601 if ( VarDeclaration* vd = v->var->isVarDeclaration() )
1602 {
1603 if ( !vd->isDataseg() )
1604 {
1605 stmt->error ( "only global variables can be referenced by identifier in naked asm" );
1606 break;
1607 }
1608
1609 // osx needs an extra underscore
1610 if ( global.params.os == OSMacOSX )
1611 insnTemplate->writestring ( "_" );
1612
1613 // print out the mangle
1614 insnTemplate->writestring ( vd->mangle() );
1615 vd->nakedUse = true;
1616 break;
1617 }
1618 }
1619 stmt->error ( "unsupported memory reference to '%s' in naked asm", e->toChars() );
1620 break;
1621
1622 default:
1623 assert ( 0 && "asm unsupported arg" );
1624 break;
1625 }
1626 }
1627 else
1628 {
1629 insnTemplate->writestring ( ( char* ) fmt );
1630 insnTemplate->printf ( "<<%s%d>>", ( mode==Mode_Input ) ?"in":"out", asmcode->args.dim );
1631 asmcode->args.push ( new AsmArg ( type, e, mode ) );
1632 }
1633 }
1634 void addOperand2 ( const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input )
1635 {
1636 assert ( !sc->func->naked );
1637 insnTemplate->writestring ( ( char* ) fmtpre );
1638 insnTemplate->printf ( "<<%s%d>>", ( mode==Mode_Input ) ?"in":"out", asmcode->args.dim );
1639 insnTemplate->writestring ( ( char* ) fmtpost );
1640 asmcode->args.push ( new AsmArg ( type, e, mode ) );
1641 }
1642
1643 void addLabel ( char* id )
1644 {
1645 insnTemplate->writestring ( sc->func->mangle() );
1646 insnTemplate->writestring ( "_" );
1647 insnTemplate->writestring ( id );
1648 }
1649
1650 /* Determines whether the operand is a register, memory reference
1651 or immediate. Immediate addresses are currently classified as
1652 memory. This function is called before the exact instructions
1653 is known and thus, should not use opInfo. */
1654 void classifyOperand ( Operand * operand )
1655 {
1656 operand->cls = classifyOperand1 ( operand );
1657 }
1658
1659 OperandClass classifyOperand1 ( Operand * operand )
1660 {
1661 bool is_localsize = false;
1662 bool really_have_symbol = false;
1663
1664 if ( operand->symbolDisplacement.dim )
1665 {
1666 is_localsize = isLocalSize ( ( Expression * ) operand->symbolDisplacement.data[0] );
1667 really_have_symbol = ! is_localsize;
1668 }
1669
1670 if ( operand->isOffset && ! operand->hasBracket )
1671 return Opr_Immediate;
1672
1673 if ( operand->hasBracket || really_have_symbol ) // %% redo for 'offset' function
1674 {
1675 if ( operand->reg != Reg_Invalid )
1676 {
1677 invalidExpression();
1678 return Opr_Invalid;
1679 }
1680
1681 return Opr_Mem;
1682 }
1683
1684 if ( operand->reg != Reg_Invalid && operand->constDisplacement != 0 )
1685 {
1686 invalidExpression();
1687 return Opr_Invalid;
1688 }
1689
1690 if ( operand->segmentPrefix != Reg_Invalid )
1691 {
1692 if ( operand->reg != Reg_Invalid )
1693 {
1694 invalidExpression();
1695 return Opr_Invalid;
1696 }
1697
1698 return Opr_Mem;
1699 }
1700
1701 if ( operand->reg != Reg_Invalid && ! operand->hasNumber )
1702 return Opr_Reg;
1703
1704 // should check immediate given (operand->hasNumber);
1705 //
1706 if ( operand->hasNumber || is_localsize )
1707 {
1708 // size determination not correct if there are symbols Opr_Immediate
1709 if ( operand->dataSize == Default_Ptr )
1710 {
1711 if ( operand->constDisplacement < 0x100 )
1712 operand->dataSize = Byte_Ptr;
1713 else if ( operand->constDisplacement < 0x10000 )
1714 operand->dataSize = Short_Ptr;
1715 else
1716 operand->dataSize = Int_Ptr;
1717 }
1718 return Opr_Immediate;
1719 }
1720
1721 // probably a bug,?
1722 stmt->error ( "invalid operand" );
1723 return Opr_Invalid;
1724 }
1725
1726 void writeReg ( Reg reg )
1727 {
1728 insnTemplate->writestring ( ( char* ) "%" );
1729 insnTemplate->write ( regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length() );
1730 }
1731
1732 bool opTakesLabel()
1733 {
1734 switch ( op )
1735 {
1736 case Op_Branch:
1737 case Op_CBranch:
1738 case Op_Loop:
1739 return true;
1740 default:
1741 return false;
1742 }
1743 }
1744
1745 bool getTypeChar ( TypeNeeded needed, PtrType ptrtype, char & type_char )
1746 {
1747 switch ( needed )
1748 {
1749 case Byte_NoType:
1750 return ptrtype == Byte_Ptr;
1751 case Word_Types:
1752 if ( ptrtype == Byte_Ptr )
1753 return false;
1754 // drop through
1755 case Int_Types:
1756 switch ( ptrtype )
1757 {
1758 case Byte_Ptr: type_char = 'b'; break;
1759 case Short_Ptr: type_char = 'w'; break;
1760 case Int_Ptr: type_char = 'l'; break;
1761 default:
1762 // %% these may be too strict
1763 return false;
1764 }
1765 break;
1766 case FPInt_Types:
1767 switch ( ptrtype )
1768 {
1769 case Short_Ptr: type_char = 0; break;
1770 case Int_Ptr: type_char = 'l'; break;
1771 case QWord_Ptr: type_char = 'q'; break;
1772 default:
1773 return false;
1774 }
1775 break;
1776 case FP_Types:
1777 switch ( ptrtype )
1778 {
1779 case Float_Ptr: type_char = 's'; break;
1780 case Double_Ptr: type_char = 'l'; break;
1781 case Extended_Ptr: type_char = 't'; break;
1782 default:
1783 return false;
1784 }
1785 break;
1786 default:
1787 return false;
1788 }
1789 return true;
1790 }
1791
1792 // also set impl clobbers
1793 bool formatInstruction ( int nOperands, AsmCode * asmcode )
1794 {
1795 const char *fmt;
1796 const char *mnemonic;
1797 char type_char = 0;
1798 bool use_star;
1799 AsmArgMode mode;
1800
1801 insnTemplate = new OutBuffer;
1802 // %% todo: special case for something..
1803 if ( opInfo->linkType == Out_Mnemonic )
1804 mnemonic = alternateMnemonics[opInfo->link];
1805 else
1806 mnemonic = opIdent->string;
1807
1808 if ( opInfo->needsType )
1809 {
1810 PtrType exact_type = Default_Ptr;
1811 PtrType min_type = Default_Ptr;
1812 PtrType hint_type = Default_Ptr;
1813
1814 /* Default types: This attempts to match the observed behavior of DMD */
1815 switch ( opInfo->needsType )
1816 {
1817 case Int_Types: min_type = Byte_Ptr; break;
1818 case Word_Types: min_type = Short_Ptr; break;
1819 case FPInt_Types:
1820 if ( op == Op_Fis_ST ) // integer math instructions
1821 min_type = Int_Ptr;
1822 else // compare, load, store
1823 min_type = Short_Ptr;
1824 break;
1825 case FP_Types: min_type = Float_Ptr; break;
1826 }
1827 if ( op == Op_push && operands[0].cls == Opr_Immediate )
1828 min_type = Int_Ptr;
1829
1830 for ( int i = 0; i < nOperands; i++ )
1831 {
1832 if ( hint_type == Default_Ptr &&
1833 ! ( opInfo->operands[i] & Opr_NoType ) )
1834 hint_type = operands[i].dataSizeHint;
1835
1836 if ( ( opInfo->operands[i] & Opr_NoType ) ||
1837 operands[i].dataSize == Default_Ptr )
1838 continue;
1839 if ( operands[i].cls == Opr_Immediate )
1840 {
1841 min_type = operands[i].dataSize > min_type ?
1842 operands[i].dataSize : min_type;
1843 }
1844 else
1845 {
1846 exact_type = operands[i].dataSize; // could check for conflicting types
1568 break; 1847 break;
1569 } 1848 }
1570 } 1849 }
1571 stmt->error("unsupported memory reference to '%s' in naked asm", e->toChars()); 1850
1851 bool type_ok;
1852 if ( exact_type == Default_Ptr )
1853 {
1854 type_ok = getTypeChar ( ( TypeNeeded ) opInfo->needsType, hint_type, type_char );
1855 if ( ! type_ok )
1856 type_ok = getTypeChar ( ( TypeNeeded ) opInfo->needsType, min_type, type_char );
1857 }
1858 else
1859 type_ok = getTypeChar ( ( TypeNeeded ) opInfo->needsType, exact_type, type_char );
1860
1861 if ( ! type_ok )
1862 {
1863 stmt->error ( "invalid operand size" );
1864 return false;
1865 }
1866 }
1867 else if ( op == Op_Branch )
1868 {
1869 if ( operands[0].dataSize == Far_Ptr ) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
1870 insnTemplate->writebyte ( 'l' );
1871 }
1872 else if ( op == Op_fxch )
1873 {
1874 // gas won't accept the two-operand form
1875 if ( operands[1].cls == Opr_Reg && operands[1].reg == Reg_ST )
1876 {
1877 nOperands = 1;
1878 }
1879 else
1880 {
1881 stmt->error ( "invalid operands" );
1882 return false;
1883 }
1884 }
1885
1886 switch ( op )
1887 {
1888 case Op_SizedStack:
1889 {
1890 int mlen = strlen ( mnemonic );
1891 if ( mnemonic[mlen-1] == 'd' )
1892 insnTemplate->write ( mnemonic, mlen-1 );
1893 else
1894 {
1895 insnTemplate->writestring ( ( char* ) mnemonic );
1896 insnTemplate->writebyte ( 'w' );
1897 }
1898 }
1572 break; 1899 break;
1573 1900 case Op_cmpsd:
1574 default: 1901 case Op_insX:
1575 assert(0 && "asm unsupported arg"); 1902 case Op_lodsX:
1903 case Op_movsd:
1904 case Op_outsX:
1905 case Op_scasX:
1906 case Op_stosX:
1907 {
1908 int mlen = strlen ( mnemonic );
1909 if ( mnemonic[mlen-1] == 'd' )
1910 {
1911 insnTemplate->write ( mnemonic, mlen-1 );
1912 insnTemplate->writebyte ( 'l' );
1913 }
1914 else
1915 {
1916 insnTemplate->writestring ( ( char* ) mnemonic );
1917 }
1918 }
1576 break; 1919 break;
1577 } 1920 case Op_movsx:
1578 } 1921 case Op_movzx:
1579 else 1922 {
1580 { 1923 char tc_1;
1581 insnTemplate->writestring((char*) fmt); 1924 int mlen = strlen ( mnemonic );
1582 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); 1925 PtrType op1_size = operands[1].dataSize;
1583 asmcode->args.push( new AsmArg(type, e, mode) ); 1926 if ( op1_size == Default_Ptr )
1584 } 1927 op1_size = operands[1].dataSizeHint;
1585 } 1928 // Need type char for source arg
1586 void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { 1929 switch ( op1_size )
1587 assert(!sc->func->naked); 1930 {
1588 insnTemplate->writestring((char*) fmtpre); 1931 case Byte_Ptr:
1589 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); 1932 case Default_Ptr:
1590 insnTemplate->writestring((char*) fmtpost); 1933 tc_1 = 'b';
1591 asmcode->args.push( new AsmArg(type, e, mode) ); 1934 break;
1592 } 1935 case Short_Ptr:
1593 1936 tc_1 = 'w';
1594 void addLabel(char* id) { 1937 break;
1595 insnTemplate->writestring(sc->func->mangle()); 1938 default:
1596 insnTemplate->writestring("_"); 1939 stmt->error ( "invalid operand size/type" );
1597 insnTemplate->writestring(id); 1940 return false;
1598 } 1941 }
1599 1942 assert ( type_char != 0 );
1600 /* Determines whether the operand is a register, memory reference 1943 insnTemplate->write ( mnemonic, mlen-1 );
1601 or immediate. Immediate addresses are currently classified as 1944 insnTemplate->writebyte ( tc_1 );
1602 memory. This function is called before the exact instructions 1945 insnTemplate->writebyte ( type_char );
1603 is known and thus, should not use opInfo. */ 1946 }
1604 void classifyOperand(Operand * operand) { 1947 break;
1605 operand->cls = classifyOperand1(operand); 1948 default:
1606 } 1949 insnTemplate->writestring ( ( char* ) mnemonic );
1607 1950 if ( type_char )
1608 OperandClass classifyOperand1(Operand * operand) { 1951 insnTemplate->writebyte ( type_char );
1609 bool is_localsize = false; 1952 break;
1610 bool really_have_symbol = false; 1953 }
1611 1954
1612 if (operand->symbolDisplacement.dim) { 1955 switch ( opInfo->implicitClobbers & Clb_DXAX_Mask )
1613 is_localsize = isLocalSize( (Expression *) operand->symbolDisplacement.data[0] ); 1956 {
1614 really_have_symbol = ! is_localsize; 1957 case Clb_SizeAX:
1615 } 1958 case Clb_EAX:
1616 1959 asmcode->regs[Reg_EAX] = true;
1617 if (operand->isOffset && ! operand->hasBracket) 1960 break;
1618 return Opr_Immediate; 1961 case Clb_SizeDXAX:
1619 1962 asmcode->regs[Reg_EAX] = true;
1620 if (operand->hasBracket || really_have_symbol) { // %% redo for 'offset' function 1963 if ( type_char != 'b' )
1621 if (operand->reg != Reg_Invalid) { 1964 asmcode->regs[Reg_EDX] = true;
1622 invalidExpression(); 1965 break;
1623 return Opr_Invalid; 1966 default:
1624 } 1967 // nothing
1625 1968 break;
1626 return Opr_Mem; 1969 }
1627 } 1970
1628 1971 if ( opInfo->implicitClobbers & Clb_DI )
1629 if (operand->reg != Reg_Invalid && operand->constDisplacement != 0) { 1972 asmcode->regs[Reg_EDI] = true;
1630 invalidExpression(); 1973 if ( opInfo->implicitClobbers & Clb_SI )
1631 return Opr_Invalid; 1974 asmcode->regs[Reg_ESI] = true;
1632 } 1975 if ( opInfo->implicitClobbers & Clb_CX )
1633 1976 asmcode->regs[Reg_ECX] = true;
1634 if (operand->segmentPrefix != Reg_Invalid) { 1977 if ( opInfo->implicitClobbers & Clb_SP )
1635 if (operand->reg != Reg_Invalid) { 1978 asmcode->regs[Reg_ESP] = true;
1636 invalidExpression(); 1979 if ( opInfo->implicitClobbers & Clb_ST )
1637 return Opr_Invalid; 1980 {
1638 } 1981 /* Can't figure out how to tell GCC that an
1639 1982 asm statement leaves an arg pushed on the stack.
1640 return Opr_Mem; 1983 Maybe if the statment had and input or output
1641 } 1984 operand it would work... In any case, clobbering
1642 1985 all FP prevents incorrect code generation. */
1643 if (operand->reg != Reg_Invalid && ! operand->hasNumber) 1986 asmcode->regs[Reg_ST] = true;
1644 return Opr_Reg; 1987 asmcode->regs[Reg_ST1] = true;
1645 1988 asmcode->regs[Reg_ST2] = true;
1646 // should check immediate given (operand->hasNumber); 1989 asmcode->regs[Reg_ST3] = true;
1647 // 1990 asmcode->regs[Reg_ST4] = true;
1648 if (operand->hasNumber || is_localsize) { 1991 asmcode->regs[Reg_ST5] = true;
1649 // size determination not correct if there are symbols Opr_Immediate 1992 asmcode->regs[Reg_ST6] = true;
1650 if (operand->dataSize == Default_Ptr) { 1993 asmcode->regs[Reg_ST7] = true;
1651 if (operand->constDisplacement < 0x100) 1994 }
1652 operand->dataSize = Byte_Ptr; 1995 if ( opInfo->implicitClobbers & Clb_Flags )
1653 else if (operand->constDisplacement < 0x10000) 1996 asmcode->regs[Reg_EFLAGS] = true;
1654 operand->dataSize = Short_Ptr; 1997 if ( op == Op_cpuid )
1655 else 1998 {
1656 operand->dataSize = Int_Ptr; 1999 asmcode->regs[Reg_EAX] = true;
1657 } 2000 asmcode->regs[Reg_ECX] = true;
1658 return Opr_Immediate; 2001 asmcode->regs[Reg_EDX] = true;
1659 } 2002 }
1660 2003
1661 // probably a bug,? 2004 insnTemplate->writebyte ( ' ' );
1662 stmt->error("invalid operand"); 2005 for ( int i__ = 0; i__ < nOperands; i__++ )
1663 return Opr_Invalid; 2006 {
1664 } 2007 int i;
1665 2008 if ( i__ != 0 )
1666 void writeReg(Reg reg) { 2009 insnTemplate->writestring ( ( char* ) ", " );
1667 insnTemplate->writestring((char*) "%"); 2010
1668 insnTemplate->write(regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length()); 2011 fmt = "$";
1669 } 2012
1670 2013 switch ( op )
1671 bool opTakesLabel() { 2014 {
1672 switch(op) { 2015 case Op_mul:
1673 case Op_Branch: 2016 // gas won't accept the two-operand form; skip to the source operand
1674 case Op_CBranch: 2017 i__ = 1;
1675 case Op_Loop: 2018 // drop through
1676 return true; 2019 case Op_bound:
1677 default: 2020 case Op_enter:
1678 return false; 2021 i = i__;
1679 } 2022 break;
1680 } 2023 default:
1681 2024 i = nOperands - 1 - i__; // operand = & operands[ nOperands - 1 - i ];
1682 bool getTypeChar(TypeNeeded needed, PtrType ptrtype, char & type_char) 2025 break;
1683 { 2026 }
1684 switch (needed) { 2027 operand = & operands[ i ];
1685 case Byte_NoType: 2028
1686 return ptrtype == Byte_Ptr; 2029 switch ( operand->cls )
1687 case Word_Types: 2030 {
1688 if (ptrtype == Byte_Ptr) 2031 case Opr_Immediate:
1689 return false; 2032 // for implementing offset:
1690 // drop through 2033 // $var + $7 // fails
1691 case Int_Types: 2034 // $var + 7 // ok
1692 switch (ptrtype) { 2035 // $7 + $var // ok
1693 case Byte_Ptr: type_char = 'b'; break; 2036
1694 case Short_Ptr: type_char = 'w'; break; 2037 // DMD doesn't seem to allow this
1695 case Int_Ptr: type_char = 'l'; break; 2038 /*
1696 default: 2039 if (opInfo->takesLabel()) tho... (near ptr <Number> would be abs?)
1697 // %% these may be too strict 2040 fmt = "$a"; // GAS won't accept "jmp $42"; must be "jmp 42" (rel) or "jmp *42" (abs)
1698 return false; 2041 */
1699 } 2042 if ( opTakesLabel() /*opInfo->takesLabel()*/ )
1700 break; 2043 {
1701 case FPInt_Types: 2044 // "relative addressing not allowed in branch instructions" ..
1702 switch (ptrtype) { 2045 stmt->error ( "integer constant not allowed in branch instructions" );
1703 case Short_Ptr: type_char = 0; break; 2046 return false;
1704 case Int_Ptr: type_char = 'l'; break; 2047 }
1705 case QWord_Ptr: type_char = 'q'; break; 2048
1706 default: 2049 if ( operand->symbolDisplacement.dim &&
1707 return false; 2050 isLocalSize ( ( Expression * ) operand->symbolDisplacement.data[0] ) )
1708 } 2051 {
1709 break; 2052 // handle __LOCAL_SIZE, which in this constant, is an immediate
1710 case FP_Types: 2053 // should do this in slotexp..
1711 switch (ptrtype) { 2054 addOperand ( "$", Arg_LocalSize,
1712 case Float_Ptr: type_char = 's'; break; 2055 ( Expression * ) operand->symbolDisplacement.data[0], asmcode );
1713 case Double_Ptr: type_char = 'l'; break; 2056 if ( operand->constDisplacement )
1714 case Extended_Ptr: type_char = 't'; break; 2057 insnTemplate->writebyte ( '+' );
1715 default: 2058 else
1716 return false; 2059 break;
1717 } 2060 }
1718 break; 2061
1719 default: 2062 if ( operand->symbolDisplacement.dim )
1720 return false; 2063 {
1721 } 2064 fmt = "$a";
1722 return true; 2065 addOperand ( "$", Arg_Pointer,
1723 } 2066 ( Expression * ) operand->symbolDisplacement.data[0],
1724 2067 asmcode );
1725 // also set impl clobbers 2068
1726 bool formatInstruction(int nOperands, AsmCode * asmcode) { 2069 if ( operand->constDisplacement )
1727 const char *fmt; 2070 insnTemplate->writebyte ( '+' );
1728 const char *mnemonic; 2071 else
1729 char type_char = 0; 2072 // skip the addOperand(fmt, Arg_Integer...) below
1730 bool use_star; 2073 break;
1731 AsmArgMode mode; 2074 }
1732 2075 addOperand ( fmt, Arg_Integer, newIntExp ( operand->constDisplacement ), asmcode );
1733 insnTemplate = new OutBuffer; 2076 break;
1734 // %% todo: special case for something.. 2077 case Opr_Reg:
1735 if (opInfo->linkType == Out_Mnemonic) 2078 if ( opInfo->operands[i] & Opr_Dest )
1736 mnemonic = alternateMnemonics[opInfo->link]; 2079 {
1737 else 2080 Reg clbr_reg = ( Reg ) regInfo[operand->reg].baseReg;
1738 mnemonic = opIdent->string; 2081 if ( clbr_reg != Reg_Invalid )
1739 2082 {
1740 if (opInfo->needsType) { 2083 asmcode->regs[clbr_reg] = true;
1741 PtrType exact_type = Default_Ptr; 2084 }
1742 PtrType min_type = Default_Ptr; 2085 }
1743 PtrType hint_type = Default_Ptr; 2086 if ( opTakesLabel() /*opInfo->takesLabel()*/ )
1744 2087 insnTemplate->writebyte ( '*' );
1745 /* Default types: This attempts to match the observed behavior of DMD */ 2088 writeReg ( operand->reg );
1746 switch (opInfo->needsType) { 2089 /*
1747 case Int_Types: min_type = Byte_Ptr; break; 2090 insnTemplate->writestring("%");
1748 case Word_Types: min_type = Short_Ptr; break; 2091 insnTemplate->writestring(regInfo[operand->reg].name);
1749 case FPInt_Types: 2092 */
1750 if (op == Op_Fis_ST) // integer math instructions 2093 break;
1751 min_type = Int_Ptr; 2094 case Opr_Mem:
1752 else // compare, load, store 2095 // better: use output operands for simple variable references
1753 min_type = Short_Ptr; 2096 if ( ( opInfo->operands[i] & Opr_Update ) == Opr_Update )
1754 break; 2097 {
1755 case FP_Types: min_type = Float_Ptr; break; 2098 mode = Mode_Update;
1756 } 2099 }
1757 if (op == Op_push && operands[0].cls == Opr_Immediate) 2100 else if ( opInfo->operands[i] & Opr_Dest )
1758 min_type = Int_Ptr; 2101 {
1759 2102 mode = Mode_Output;
1760 for (int i = 0; i < nOperands; i++) { 2103 }
1761 if (hint_type == Default_Ptr && 2104 else
1762 ! (opInfo->operands[i] & Opr_NoType)) 2105 {
1763 hint_type = operands[i].dataSizeHint; 2106 mode = Mode_Input;
1764 2107 }
1765 if ((opInfo->operands[i] & Opr_NoType) || 2108
1766 operands[i].dataSize == Default_Ptr) 2109 use_star = opTakesLabel();//opInfo->takesLabel();
1767 continue; 2110 if ( operand->segmentPrefix != Reg_Invalid )
1768 if (operands[i].cls == Opr_Immediate) { 2111 {
1769 min_type = operands[i].dataSize > min_type ? 2112 writeReg ( operand->segmentPrefix );
1770 operands[i].dataSize : min_type; 2113 insnTemplate->writebyte ( ':' );
1771 } else { 2114 }
1772 exact_type = operands[i].dataSize; // could check for conflicting types 2115 if ( operand->symbolDisplacement.dim )
1773 break; 2116 {
1774 } 2117 Expression * e = ( Expression * ) operand->symbolDisplacement.data[0];
1775 } 2118 Declaration * decl = 0;
1776 2119
1777 bool type_ok; 2120 if ( e->op == TOKvar )
1778 if (exact_type == Default_Ptr) { 2121 decl = ( ( VarExp * ) e )->var;
1779 type_ok = getTypeChar((TypeNeeded) opInfo->needsType, hint_type, type_char); 2122
1780 if (! type_ok) 2123 if ( operand->baseReg != Reg_Invalid &&
1781 type_ok = getTypeChar((TypeNeeded) opInfo->needsType, min_type, type_char); 2124 decl && ! decl->isDataseg() )
1782 } else 2125 {
1783 type_ok = getTypeChar((TypeNeeded) opInfo->needsType, exact_type, type_char); 2126
1784 2127 // Use the offset from frame pointer
1785 if (! type_ok) { 2128
1786 stmt->error("invalid operand size"); 2129 /* GCC doesn't give the front end access to stack offsets
1787 return false; 2130 when optimization is turned on (3.x) or at all (4.x).
1788 } 2131
1789 } else if (op == Op_Branch) { 2132 Try to convert var[EBP] (or var[ESP] for naked funcs) to
1790 if (operands[0].dataSize == Far_Ptr) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that.. 2133 a memory expression that does not require us to know
1791 insnTemplate->writebyte('l'); 2134 the stack offset.
1792 } else if (op == Op_fxch) { 2135 */
1793 // gas won't accept the two-operand form 2136
1794 if (operands[1].cls == Opr_Reg && operands[1].reg == Reg_ST) { 2137 if ( operand->indexReg == Reg_Invalid &&
1795 nOperands = 1; 2138 decl->isVarDeclaration() &&
1796 } else { 2139 ( ( ( operand->baseReg == Reg_EBP || ( operand->baseReg == Reg_RBP ) ) && ! sc->func->naked ) ||
1797 stmt->error("invalid operands"); 2140 ( ( operand->baseReg == Reg_ESP || ( operand->baseReg == Reg_RSP ) ) && sc->func->naked ) ) )
1798 return false; 2141 {
1799 } 2142
1800 } 2143 if ( mode == Mode_Output )
1801 2144 {
1802 switch (op) { 2145 e = new AddrExp ( 0, e );
1803 case Op_SizedStack: 2146 e->type = decl->type->pointerTo();
1804 { 2147 }
1805 int mlen = strlen(mnemonic);
1806 if (mnemonic[mlen-1] == 'd')
1807 insnTemplate->write(mnemonic, mlen-1);
1808 else {
1809 insnTemplate->writestring((char*) mnemonic);
1810 insnTemplate->writebyte('w');
1811 }
1812 }
1813 break;
1814 case Op_cmpsd:
1815 case Op_insX:
1816 case Op_lodsX:
1817 case Op_movsd:
1818 case Op_outsX:
1819 case Op_scasX:
1820 case Op_stosX:
1821 {
1822 int mlen = strlen(mnemonic);
1823 if (mnemonic[mlen-1] == 'd') {
1824 insnTemplate->write(mnemonic, mlen-1);
1825 insnTemplate->writebyte('l');
1826 } else {
1827 insnTemplate->writestring((char*) mnemonic);
1828 }
1829 }
1830 break;
1831 case Op_movsx:
1832 case Op_movzx:
1833 {
1834 char tc_1;
1835 int mlen = strlen(mnemonic);
1836 PtrType op1_size = operands[1].dataSize;
1837 if (op1_size == Default_Ptr)
1838 op1_size = operands[1].dataSizeHint;
1839 // Need type char for source arg
1840 switch (op1_size) {
1841 case Byte_Ptr:
1842 case Default_Ptr:
1843 tc_1 = 'b';
1844 break;
1845 case Short_Ptr:
1846 tc_1 = 'w';
1847 break;
1848 default:
1849 stmt->error("invalid operand size/type");
1850 return false;
1851 }
1852 assert(type_char != 0);
1853 insnTemplate->write(mnemonic, mlen-1);
1854 insnTemplate->writebyte(tc_1);
1855 insnTemplate->writebyte(type_char);
1856 }
1857 break;
1858 default:
1859 insnTemplate->writestring((char*) mnemonic);
1860 if (type_char)
1861 insnTemplate->writebyte(type_char);
1862 break;
1863 }
1864
1865 switch (opInfo->implicitClobbers & Clb_DXAX_Mask) {
1866 case Clb_SizeAX:
1867 case Clb_EAX:
1868 asmcode->regs[Reg_EAX] = true;
1869 break;
1870 case Clb_SizeDXAX:
1871 asmcode->regs[Reg_EAX] = true;
1872 if (type_char != 'b')
1873 asmcode->regs[Reg_EDX] = true;
1874 break;
1875 default:
1876 // nothing
1877 break;
1878 }
1879
1880 if (opInfo->implicitClobbers & Clb_DI)
1881 asmcode->regs[Reg_EDI] = true;
1882 if (opInfo->implicitClobbers & Clb_SI)
1883 asmcode->regs[Reg_ESI] = true;
1884 if (opInfo->implicitClobbers & Clb_CX)
1885 asmcode->regs[Reg_ECX] = true;
1886 if (opInfo->implicitClobbers & Clb_SP)
1887 asmcode->regs[Reg_ESP] = true;
1888 if (opInfo->implicitClobbers & Clb_ST)
1889 {
1890 /* Can't figure out how to tell GCC that an
1891 asm statement leaves an arg pushed on the stack.
1892 Maybe if the statment had and input or output
1893 operand it would work... In any case, clobbering
1894 all FP prevents incorrect code generation. */
1895 asmcode->regs[Reg_ST] = true;
1896 asmcode->regs[Reg_ST1] = true;
1897 asmcode->regs[Reg_ST2] = true;
1898 asmcode->regs[Reg_ST3] = true;
1899 asmcode->regs[Reg_ST4] = true;
1900 asmcode->regs[Reg_ST5] = true;
1901 asmcode->regs[Reg_ST6] = true;
1902 asmcode->regs[Reg_ST7] = true;
1903 }
1904 if (opInfo->implicitClobbers & Clb_Flags)
1905 asmcode->regs[Reg_EFLAGS] = true;
1906 if (op == Op_cpuid) {
1907 asmcode->regs[Reg_EAX] = true;
1908 asmcode->regs[Reg_ECX] = true;
1909 asmcode->regs[Reg_EDX] = true;
1910 }
1911
1912 insnTemplate->writebyte(' ');
1913 for (int i__ = 0; i__ < nOperands; i__++) {
1914 int i;
1915 if (i__ != 0)
1916 insnTemplate->writestring((char*) ", ");
1917
1918 fmt = "$";
1919
1920 switch (op) {
1921 case Op_mul:
1922 // gas won't accept the two-operand form; skip to the source operand
1923 i__ = 1;
1924 // drop through
1925 case Op_bound:
1926 case Op_enter:
1927 i = i__;
1928 break;
1929 default:
1930 i = nOperands - 1 - i__; // operand = & operands[ nOperands - 1 - i ];
1931 break;
1932 }
1933 operand = & operands[ i ];
1934
1935 switch (operand->cls) {
1936 case Opr_Immediate:
1937 // for implementing offset:
1938 // $var + $7 // fails
1939 // $var + 7 // ok
1940 // $7 + $var // ok
1941
1942 // DMD doesn't seem to allow this
1943 /*
1944 if (opInfo->takesLabel()) tho... (near ptr <Number> would be abs?)
1945 fmt = "$a"; // GAS won't accept "jmp $42"; must be "jmp 42" (rel) or "jmp *42" (abs)
1946 */
1947 if (opTakesLabel()/*opInfo->takesLabel()*/) {
1948 // "relative addressing not allowed in branch instructions" ..
1949 stmt->error("integer constant not allowed in branch instructions");
1950 return false;
1951 }
1952
1953 if (operand->symbolDisplacement.dim &&
1954 isLocalSize( (Expression *) operand->symbolDisplacement.data[0] )) {
1955 // handle __LOCAL_SIZE, which in this constant, is an immediate
1956 // should do this in slotexp..
1957 addOperand("$", Arg_LocalSize,
1958 (Expression *) operand->symbolDisplacement.data[0], asmcode);
1959 if (operand->constDisplacement)
1960 insnTemplate->writebyte('+');
1961 else
1962 break;
1963 }
1964
1965 if (operand->symbolDisplacement.dim) {
1966 fmt = "$a";
1967 addOperand("$", Arg_Pointer,
1968 (Expression *) operand->symbolDisplacement.data[0],
1969 asmcode);
1970
1971 if (operand->constDisplacement)
1972 insnTemplate->writebyte('+');
1973 else
1974 // skip the addOperand(fmt, Arg_Integer...) below
1975 break;
1976 }
1977 addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
1978 break;
1979 case Opr_Reg:
1980 if (opInfo->operands[i] & Opr_Dest) {
1981 Reg clbr_reg = (Reg) regInfo[operand->reg].baseReg;
1982 if (clbr_reg != Reg_Invalid) {
1983 asmcode->regs[clbr_reg] = true;
1984 }
1985 }
1986 if (opTakesLabel()/*opInfo->takesLabel()*/)
1987 insnTemplate->writebyte('*');
1988 writeReg(operand->reg);
1989 /*
1990 insnTemplate->writestring("%");
1991 insnTemplate->writestring(regInfo[operand->reg].name);
1992 */
1993 break;
1994 case Opr_Mem:
1995 // better: use output operands for simple variable references
1996 if ( (opInfo->operands[i] & Opr_Update) == Opr_Update) {
1997 mode = Mode_Update;
1998 } else if (opInfo->operands[i] & Opr_Dest) {
1999 mode = Mode_Output;
2000 } else {
2001 mode = Mode_Input;
2002 }
2003
2004 use_star = opTakesLabel();//opInfo->takesLabel();
2005 if (operand->segmentPrefix != Reg_Invalid) {
2006 writeReg(operand->segmentPrefix);
2007 insnTemplate->writebyte(':');
2008 }
2009 if (operand->symbolDisplacement.dim) {
2010 Expression * e = (Expression *) operand->symbolDisplacement.data[0];
2011 Declaration * decl = 0;
2012
2013 if (e->op == TOKvar)
2014 decl = ((VarExp *) e)->var;
2015
2016 if (operand->baseReg != Reg_Invalid &&
2017 decl && ! decl->isDataseg()) {
2018
2019 // Use the offset from frame pointer
2020
2021 /* GCC doesn't give the front end access to stack offsets
2022 when optimization is turned on (3.x) or at all (4.x).
2023
2024 Try to convert var[EBP] (or var[ESP] for naked funcs) to
2025 a memory expression that does not require us to know
2026 the stack offset.
2027 */
2028
2029 if (operand->indexReg == Reg_Invalid &&
2030 decl->isVarDeclaration() &&
2031 ( ((operand->baseReg == Reg_EBP || (operand->baseReg == Reg_RBP)) && ! sc->func->naked ) ||
2032 ((operand->baseReg == Reg_ESP || (operand->baseReg == Reg_RSP)) && sc->func->naked)) )
2033 {
2034
2035 if (mode == Mode_Output)
2036 {
2037 e = new AddrExp(0, e);
2038 e->type = decl->type->pointerTo();
2039 }
2040 2148
2041 #if !IN_LLVM 2149 #if !IN_LLVM
2042 /* DMD uses the same frame offsets for naked functions. */ 2150 /* DMD uses the same frame offsets for naked functions. */
2043 if (sc->func->naked) 2151 if ( sc->func->naked )
2044 operand->constDisplacement += 4; 2152 operand->constDisplacement += 4;
2045 2153
2046 if (operand->constDisplacement) { 2154 if ( operand->constDisplacement )
2047 e = new AddExp(0, e, 2155 {
2048 new IntegerExp(0, operand->constDisplacement, 2156 e = new AddExp ( 0, e,
2049 Type::tint32)); 2157 new IntegerExp ( 0, operand->constDisplacement,
2050 e->type = decl->type->pointerTo(); 2158 Type::tint32 ) );
2051 } 2159 e->type = decl->type->pointerTo();
2052 e = new PtrExp(0, e); 2160 }
2053 e->type = decl->type; 2161 e = new PtrExp ( 0, e );
2162 e->type = decl->type;
2054 #endif 2163 #endif
2055 operand->constDisplacement = 0; 2164 operand->constDisplacement = 0;
2056 operand->baseReg = Reg_Invalid; 2165 operand->baseReg = Reg_Invalid;
2057 2166
2058 addOperand(fmt, Arg_Memory, e, asmcode, mode); 2167 addOperand ( fmt, Arg_Memory, e, asmcode, mode );
2059 2168
2060 } else { 2169 }
2061 addOperand2("${",":a}", Arg_FrameRelative, e, asmcode); 2170 else
2062 } 2171 {
2063 if (opInfo->operands[i] & Opr_Dest) 2172 // FIXME: what is this ?
2064 asmcode->clobbersMemory = 1; 2173 addOperand2 ( "${",":a}", Arg_FrameRelative, e, asmcode );
2065 } else { 2174 }
2066 // Plain memory reference to variable 2175 if ( opInfo->operands[i] & Opr_Dest )
2067 2176 asmcode->clobbersMemory = 1;
2068 /* If in a reg, DMD moves to memory.. even with -O, so we'll do the same 2177 }
2069 by always using the "m" contraint. 2178 else
2070 2179 {
2071 In order to get the correct output for function and label symbols, 2180 // Plain memory reference to variable
2072 the %an format must be used with the "p" constraint. 2181
2073 */ 2182 /* If in a reg, DMD moves to memory.. even with -O, so we'll do the same
2074 if (isDollar(e)) { 2183 by always using the "m" contraint.
2075 error("dollar labels are not supported", stmt->loc.toChars()); 2184
2076 asmcode->dollarLabel = 1; 2185 In order to get the correct output for function and label symbols,
2077 } else if (e->op == TOKdsymbol) { 2186 the %an format must be used with the "p" constraint.
2078 LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s; 2187 */
2079 stmt->isBranchToLabel = lbl->ident; 2188 if ( isDollar ( e ) )
2080 2189 {
2081 use_star = false; 2190 error ( "dollar labels are not supported", stmt->loc.toChars() );
2082 addLabel(lbl->ident->toChars()); 2191 asmcode->dollarLabel = 1;
2083 } else if ((decl && decl->isCodeseg())) { // if function or label 2192 }
2084 use_star = false; 2193 else if ( e->op == TOKdsymbol )
2085 addOperand2("${", ":c}", Arg_Pointer, e, asmcode); 2194 {
2086 } else { 2195 LabelDsymbol * lbl = ( LabelDsymbol * ) ( ( DsymbolExp * ) e )->s;
2087 if (use_star) { 2196 stmt->isBranchToLabel = lbl->ident;
2088 insnTemplate->writebyte('*'); 2197
2089 use_star = false; 2198 use_star = false;
2090 } 2199 addLabel ( lbl->ident->toChars() );
2091 2200 }
2092 if (!sc->func->naked) { // no addrexp in naked asm please :) 2201 else if ( ( decl && decl->isCodeseg() ) ) // if function or label
2093 Type* tt = e->type->pointerTo(); 2202 {
2094 e = new AddrExp(0, e); 2203 use_star = false;
2095 e->type = tt; 2204 // simply write out the mangle
2096 } 2205 // on osx, prepend extra _
2097 2206 if ( global.params.os == OSMacOSX )
2098 addOperand(fmt, Arg_Memory, e, asmcode, mode); 2207 insnTemplate->writestring ( "_" );
2099 } 2208 insnTemplate->writestring ( decl->mangle() );
2100 } 2209 // addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
2101 } 2210 }
2102 if (use_star) 2211 else
2103 insnTemplate->writebyte('*'); 2212 {
2104 if (operand->segmentPrefix != Reg_Invalid || operand->constDisplacement) { 2213 if ( use_star )
2105 if (operand->symbolDisplacement.dim) 2214 {
2106 insnTemplate->writebyte('+'); 2215 insnTemplate->writebyte ( '*' );
2107 //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode); 2216 use_star = false;
2108 insnTemplate->printf("%d", operand->constDisplacement); 2217 }
2109 if (opInfo->operands[i] & Opr_Dest) 2218
2110 asmcode->clobbersMemory = 1; 2219 if ( !sc->func->naked ) // no addrexp in naked asm please :)
2111 } 2220 {
2112 if (operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid) { 2221 Type* tt = e->type->pointerTo();
2113 insnTemplate->writebyte('('); 2222 e = new AddrExp ( 0, e );
2114 if (operand->baseReg != Reg_Invalid) 2223 e->type = tt;
2115 writeReg(operand->baseReg); 2224 }
2116 if (operand->indexReg != Reg_Invalid) { 2225
2117 insnTemplate->writebyte(','); 2226 addOperand ( fmt, Arg_Memory, e, asmcode, mode );
2118 writeReg(operand->indexReg); 2227 }
2119 if (operand->scale) { 2228 }
2120 insnTemplate->printf(",%d", operand->scale); 2229 }
2121 } 2230 if ( use_star )
2122 } 2231 insnTemplate->writebyte ( '*' );
2123 insnTemplate->writebyte(')'); 2232 if ( operand->segmentPrefix != Reg_Invalid || operand->constDisplacement )
2124 if (opInfo->operands[i] & Opr_Dest) 2233 {
2125 asmcode->clobbersMemory = 1; 2234 if ( operand->symbolDisplacement.dim )
2126 } 2235 insnTemplate->writebyte ( '+' );
2127 break; 2236 //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
2128 case Opr_Invalid: 2237 insnTemplate->printf ( "%d", operand->constDisplacement );
2129 return false; 2238 if ( opInfo->operands[i] & Opr_Dest )
2130 } 2239 asmcode->clobbersMemory = 1;
2131 } 2240 }
2132 2241 if ( operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid )
2133 asmcode->insnTemplateLen = insnTemplate->offset; 2242 {
2134 asmcode->insnTemplate = (char*) insnTemplate->extractData(); 2243 insnTemplate->writebyte ( '(' );
2135 return true; 2244 if ( operand->baseReg != Reg_Invalid )
2136 } 2245 writeReg ( operand->baseReg );
2137 2246 if ( operand->indexReg != Reg_Invalid )
2138 bool isIntExp(Expression * exp) { 2247 {
2139 if (exp->op == TOKint64) 2248 insnTemplate->writebyte ( ',' );
2140 return 1; 2249 writeReg ( operand->indexReg );
2141 if (exp->op == TOKvar) { 2250 if ( operand->scale )
2142 Declaration * v = ((VarExp *) exp)->var; 2251 {
2143 if (v->isConst() && v->type->isintegral()) 2252 insnTemplate->printf ( ",%d", operand->scale );
2144 return 1; 2253 }
2145 } 2254 }
2146 return 0; 2255 insnTemplate->writebyte ( ')' );
2147 } 2256 if ( opInfo->operands[i] & Opr_Dest )
2148 bool isRegExp(Expression * exp) { return exp->op == TOKmod; } // ewww.%% 2257 asmcode->clobbersMemory = 1;
2149 bool isLocalSize(Expression * exp) { 2258 }
2150 // cleanup: make a static var 2259 break;
2151 return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__LOCAL_SIZE; 2260 case Opr_Invalid:
2152 } 2261 return false;
2153 bool isDollar(Expression * exp) { 2262 }
2154 return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__dollar; 2263 }
2155 } 2264
2156 2265 asmcode->insnTemplateLen = insnTemplate->offset;
2157 Expression * newRegExp(int regno) { 2266 asmcode->insnTemplate = ( char* ) insnTemplate->extractData();
2158 IntegerExp * e = new IntegerExp(regno); 2267 return true;
2159 e->op = TOKmod; 2268 }
2160 return e; 2269
2161 } 2270 bool isIntExp ( Expression * exp )
2162 2271 {
2163 Expression * newIntExp(int v /* %% type */) { 2272 if ( exp->op == TOKint64 )
2164 // Only handles 32-bit numbers as this is IA-32. 2273 return 1;
2165 return new IntegerExp(stmt->loc, v, Type::tint32); 2274 if ( exp->op == TOKvar )
2166 } 2275 {
2167 2276 Declaration * v = ( ( VarExp * ) exp )->var;
2168 void slotExp(Expression * exp) { 2277 if ( v->isConst() && v->type->isintegral() )
2169 /* 2278 return 1;
2170 if offset, make a note 2279 }
2171 2280 return 0;
2172 if integer, add to immediate 2281 }
2173 if reg: 2282 bool isRegExp ( Expression * exp ) { return exp->op == TOKmod; } // ewww.%%
2174 if not in bracket, set reg (else error) 2283 bool isLocalSize ( Expression * exp )
2175 if in bracket: 2284 {
2176 if not base, set base 2285 // cleanup: make a static var
2177 if not index, set index 2286 return exp->op == TOKidentifier && ( ( IdentifierExp * ) exp )->ident == Id::__LOCAL_SIZE;
2178 else, error 2287 }
2179 if symbol: 2288 bool isDollar ( Expression * exp )
2180 set symbol field 2289 {
2181 */ 2290 return exp->op == TOKidentifier && ( ( IdentifierExp * ) exp )->ident == Id::__dollar;
2182 2291 }
2183 bool is_offset = false; 2292
2184 if (exp->op == TOKaddress) { 2293 Expression * newRegExp ( int regno )
2185 exp = ((AddrExp *) exp)->e1; 2294 {
2186 is_offset = true; 2295 IntegerExp * e = new IntegerExp ( regno );
2187 } 2296 e->op = TOKmod;
2188 2297 return e;
2189 if (isIntExp(exp)) { 2298 }
2190 if (is_offset) 2299
2191 invalidExpression(); 2300 Expression * newIntExp ( int v /* %% type */ )
2192 operand->constDisplacement += exp->toInteger(); 2301 {
2193 if (! operand->inBracket) 2302 // Only handles 32-bit numbers as this is IA-32.
2194 operand->hasNumber = 1; 2303 return new IntegerExp ( stmt->loc, v, Type::tint32 );
2195 } else if (isRegExp(exp)) { 2304 }
2196 if (is_offset) 2305
2197 invalidExpression(); 2306 void slotExp ( Expression * exp )
2198 if (! operand->inBracket) { 2307 {
2199 if (operand->reg == Reg_Invalid) 2308 /*
2200 operand->reg = (Reg) exp->toInteger(); 2309 if offset, make a note
2201 else 2310
2202 stmt->error("too many registers in operand (use brackets)"); 2311 if integer, add to immediate
2203 } else { 2312 if reg:
2204 if (operand->baseReg == Reg_Invalid) 2313 if not in bracket, set reg (else error)
2205 operand->baseReg = (Reg) exp->toInteger(); 2314 if in bracket:
2206 else if (operand->indexReg == Reg_Invalid) { 2315 if not base, set base
2207 operand->indexReg = (Reg) exp->toInteger(); 2316 if not index, set index
2208 operand->scale = 1; 2317 else, error
2209 } else { 2318 if symbol:
2210 stmt->error("too many registers memory operand"); 2319 set symbol field
2211 } 2320 */
2212 } 2321
2213 } else if (exp->op == TOKvar) { 2322 bool is_offset = false;
2214 VarDeclaration * v = ((VarExp *) exp)->var->isVarDeclaration(); 2323 if ( exp->op == TOKaddress )
2215 2324 {
2216 if (v && v->storage_class & STCfield) { 2325 exp = ( ( AddrExp * ) exp )->e1;
2217 operand->constDisplacement += v->offset; 2326 is_offset = true;
2218 if (! operand->inBracket) 2327 }
2219 operand->hasNumber = 1; 2328
2220 } else { 2329 if ( isIntExp ( exp ) )
2221 if (v && v->type->isscalar()) 2330 {
2222 { 2331 if ( is_offset )
2223 // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64 2332 invalidExpression();
2224 TY ty = v->type->toBasetype()->ty; 2333 operand->constDisplacement += exp->toInteger();
2225 operand->dataSizeHint = ty == Tfloat80 || ty == Timaginary80 ? 2334 if ( ! operand->inBracket )
2226 Extended_Ptr : (PtrType) v->type->size(0); 2335 operand->hasNumber = 1;
2227 } 2336 }
2228 2337 else if ( isRegExp ( exp ) )
2229 if (! operand->symbolDisplacement.dim) { 2338 {
2230 if (is_offset && ! operand->inBracket) 2339 if ( is_offset )
2231 operand->isOffset = 1; 2340 invalidExpression();
2232 operand->symbolDisplacement.push( exp ); 2341 if ( ! operand->inBracket )
2233 } else { 2342 {
2234 stmt->error("too many symbols in operand"); 2343 if ( operand->reg == Reg_Invalid )
2235 } 2344 operand->reg = ( Reg ) exp->toInteger();
2236 } 2345 else
2237 } else if (exp->op == TOKidentifier || exp->op == TOKdsymbol) { 2346 stmt->error ( "too many registers in operand (use brackets)" );
2238 // %% localsize could be treated as a simple constant.. 2347 }
2239 // change to addSymbolDisp(e) 2348 else
2240 if (! operand->symbolDisplacement.dim) { 2349 {
2241 operand->symbolDisplacement.push( exp ); 2350 if ( operand->baseReg == Reg_Invalid )
2242 } else { 2351 operand->baseReg = ( Reg ) exp->toInteger();
2243 stmt->error("too many symbols in operand"); 2352 else if ( operand->indexReg == Reg_Invalid )
2244 } 2353 {
2245 } else if (exp == Handled) { 2354 operand->indexReg = ( Reg ) exp->toInteger();
2246 // nothing 2355 operand->scale = 1;
2247 } else { 2356 }
2248 stmt->error("invalid operand"); 2357 else
2249 } 2358 {
2250 } 2359 stmt->error ( "too many registers memory operand" );
2251 2360 }
2252 void invalidExpression() { 2361 }
2253 // %% report operand number 2362 }
2254 stmt->error("invalid expression"); 2363 else if ( exp->op == TOKvar )
2255 } 2364 {
2256 2365 VarDeclaration * v = ( ( VarExp * ) exp )->var->isVarDeclaration();
2257 Expression * intOp(TOK op, Expression * e1, Expression * e2) { 2366
2258 Expression * e; 2367 if ( v && v->storage_class & STCfield )
2259 if (isIntExp(e1) && (! e2 || isIntExp(e2))) { 2368 {
2260 switch (op) { 2369 operand->constDisplacement += v->offset;
2261 case TOKadd: 2370 if ( ! operand->inBracket )
2262 if (e2) 2371 operand->hasNumber = 1;
2263 e = new AddExp(stmt->loc, e1, e2); 2372 }
2264 else 2373 else
2265 e = e1; 2374 {
2266 break; 2375 if ( v && v->type->isscalar() )
2267 case TOKmin: 2376 {
2268 if (e2) 2377 // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64
2269 e = new MinExp(stmt->loc, e1, e2); 2378 TY ty = v->type->toBasetype()->ty;
2270 else 2379 operand->dataSizeHint = ty == Tfloat80 || ty == Timaginary80 ?
2271 e = new NegExp(stmt->loc, e1); 2380 Extended_Ptr : ( PtrType ) v->type->size ( 0 );
2272 break; 2381 }
2273 case TOKmul: 2382
2274 e = new MulExp(stmt->loc, e1, e2); 2383 if ( ! operand->symbolDisplacement.dim )
2275 break; 2384 {
2276 case TOKdiv: 2385 if ( is_offset && ! operand->inBracket )
2277 e = new DivExp(stmt->loc, e1, e2); 2386 operand->isOffset = 1;
2278 break; 2387 operand->symbolDisplacement.push ( exp );
2279 case TOKmod: 2388 }
2280 e = new ModExp(stmt->loc, e1, e2); 2389 else
2281 break; 2390 {
2282 case TOKshl: 2391 stmt->error ( "too many symbols in operand" );
2283 e = new ShlExp(stmt->loc, e1, e2); 2392 }
2284 break; 2393 }
2285 case TOKshr: 2394 }
2286 e = new ShrExp(stmt->loc, e1, e2); 2395 else if ( exp->op == TOKidentifier || exp->op == TOKdsymbol )
2287 break; 2396 {
2288 case TOKushr: 2397 // %% localsize could be treated as a simple constant..
2289 e = new UshrExp(stmt->loc, e1, e2); 2398 // change to addSymbolDisp(e)
2290 break; 2399 if ( ! operand->symbolDisplacement.dim )
2291 case TOKnot: 2400 {
2292 e = new NotExp(stmt->loc, e1); 2401 operand->symbolDisplacement.push ( exp );
2293 break; 2402 }
2294 case TOKtilde: 2403 else
2295 e = new ComExp(stmt->loc, e1); 2404 {
2296 break; 2405 stmt->error ( "too many symbols in operand" );
2297 default: 2406 }
2298 assert(0); 2407 }
2299 } 2408 else if ( exp == Handled )
2300 e = e->semantic(sc); 2409 {
2301 return e->optimize(WANTvalue | WANTinterpret); 2410 // nothing
2302 } else { 2411 }
2303 stmt->error("expected integer operand(s) for '%s'", Token::tochars[op]); 2412 else
2304 return newIntExp(0); 2413 {
2305 } 2414 stmt->error ( "invalid operand" );
2306 } 2415 }
2307 2416 }
2308 void parseOperand() { 2417
2309 Expression * exp = parseAsmExp(); 2418 void invalidExpression()
2310 slotExp(exp); 2419 {
2311 if (isRegExp(exp)) 2420 // %% report operand number
2312 operand->dataSize = (PtrType) regInfo[exp->toInteger()].size; 2421 stmt->error ( "invalid expression" );
2313 } 2422 }
2314 2423
2315 Expression * parseAsmExp() { 2424 Expression * intOp ( TOK op, Expression * e1, Expression * e2 )
2316 return parseShiftExp(); 2425 {
2317 } 2426 Expression * e;
2318 2427 if ( isIntExp ( e1 ) && ( ! e2 || isIntExp ( e2 ) ) )
2319 Expression * parseShiftExp() { 2428 {
2320 Expression * e1 = parseAddExp(); 2429 switch ( op )
2321 Expression * e2; 2430 {
2322 2431 case TOKadd:
2323 while (1) { 2432 if ( e2 )
2324 TOK tv = token->value; 2433 e = new AddExp ( stmt->loc, e1, e2 );
2325 switch (tv) { 2434 else
2326 case TOKshl: 2435 e = e1;
2327 case TOKshr: 2436 break;
2328 case TOKushr: 2437 case TOKmin:
2329 nextToken(); 2438 if ( e2 )
2330 e2 = parseAddExp(); 2439 e = new MinExp ( stmt->loc, e1, e2 );
2331 e1 = intOp(tv, e1, e2); 2440 else
2332 continue; 2441 e = new NegExp ( stmt->loc, e1 );
2333 default: 2442 break;
2334 break; 2443 case TOKmul:
2335 } 2444 e = new MulExp ( stmt->loc, e1, e2 );
2336 break; 2445 break;
2337 } 2446 case TOKdiv:
2338 return e1; 2447 e = new DivExp ( stmt->loc, e1, e2 );
2339 } 2448 break;
2340 2449 case TOKmod:
2341 Expression * parseAddExp() { 2450 e = new ModExp ( stmt->loc, e1, e2 );
2342 Expression * e1 = parseMultExp(); 2451 break;
2343 Expression * e2; 2452 case TOKshl:
2344 2453 e = new ShlExp ( stmt->loc, e1, e2 );
2345 while (1) { 2454 break;
2346 TOK tv = token->value; 2455 case TOKshr:
2347 switch (tv) { 2456 e = new ShrExp ( stmt->loc, e1, e2 );
2348 case TOKadd: 2457 break;
2349 nextToken(); 2458 case TOKushr:
2350 e2 = parseMultExp(); 2459 e = new UshrExp ( stmt->loc, e1, e2 );
2351 if (isIntExp(e1) && isIntExp(e2)) 2460 break;
2352 e1 = intOp(tv, e1, e2); 2461 case TOKnot:
2353 else { 2462 e = new NotExp ( stmt->loc, e1 );
2354 slotExp(e1); 2463 break;
2355 slotExp(e2); 2464 case TOKtilde:
2356 e1 = Handled; 2465 e = new ComExp ( stmt->loc, e1 );
2357 } 2466 break;
2358 continue; 2467 default:
2359 case TOKmin: 2468 assert ( 0 );
2360 // Note: no support for symbol address difference 2469 }
2361 nextToken(); 2470 e = e->semantic ( sc );
2362 e2 = parseMultExp(); 2471 return e->optimize ( WANTvalue | WANTinterpret );
2363 if (isIntExp(e1) && isIntExp(e2)) 2472 }
2364 e1 = intOp(tv, e1, e2); 2473 else
2365 else { 2474 {
2366 slotExp(e1); 2475 stmt->error ( "expected integer operand(s) for '%s'", Token::tochars[op] );
2367 e2 = intOp(TOKmin, e2, NULL); // verifies e2 is an int 2476 return newIntExp ( 0 );
2368 slotExp(e2); 2477 }
2369 e1 = Handled; 2478 }
2370 } 2479
2371 continue; 2480 void parseOperand()
2372 default: 2481 {
2373 break; 2482 Expression * exp = parseAsmExp();
2374 } 2483 slotExp ( exp );
2375 break; 2484 if ( isRegExp ( exp ) )
2376 } 2485 operand->dataSize = ( PtrType ) regInfo[exp->toInteger() ].size;
2377 return e1; 2486 }
2378 } 2487
2379 2488 Expression * parseAsmExp()
2380 bool tryScale(Expression * e1, Expression * e2) { 2489 {
2381 Expression * et; 2490 return parseShiftExp();
2382 if (isIntExp(e1) && isRegExp(e2)) { 2491 }
2383 et = e1; 2492
2384 e1 = e2; 2493 Expression * parseShiftExp()
2385 e2 = et; 2494 {
2386 goto do_scale; 2495 Expression * e1 = parseAddExp();
2387 } else if (isRegExp(e1) && isIntExp(e2)) { 2496 Expression * e2;
2388 do_scale: 2497
2389 if (! operand->inBracket) { 2498 while ( 1 )
2390 invalidExpression(); // maybe should allow, e.g. DS:EBX+EAX*4 2499 {
2391 } 2500 TOK tv = token->value;
2392 2501 switch ( tv )
2393 if (operand->scale || operand->indexReg != Reg_Invalid) { 2502 {
2394 invalidExpression(); 2503 case TOKshl:
2395 return true; 2504 case TOKshr:
2396 } 2505 case TOKushr:
2397 2506 nextToken();
2398 operand->indexReg = (Reg) e1->toInteger(); 2507 e2 = parseAddExp();
2399 operand->scale = e2->toInteger(); 2508 e1 = intOp ( tv, e1, e2 );
2400 switch (operand->scale) { 2509 continue;
2401 case 1: 2510 default:
2402 case 2: 2511 break;
2403 case 4: 2512 }
2404 case 8: 2513 break;
2405 // ok; do nothing 2514 }
2406 break; 2515 return e1;
2407 default: 2516 }
2408 stmt->error("invalid index register scale '%d'", operand->scale); 2517
2409 return true; 2518 Expression * parseAddExp()
2410 } 2519 {
2411 2520 Expression * e1 = parseMultExp();
2412 return true; 2521 Expression * e2;
2413 } 2522
2414 return false; 2523 while ( 1 )
2415 } 2524 {
2416 2525 TOK tv = token->value;
2417 Expression * parseMultExp() { 2526 switch ( tv )
2418 Expression * e1 = parseBrExp(); 2527 {
2419 Expression * e2; 2528 case TOKadd:
2420 2529 nextToken();
2421 while (1) { 2530 e2 = parseMultExp();
2422 TOK tv = token->value; 2531 if ( isIntExp ( e1 ) && isIntExp ( e2 ) )
2423 switch (tv) { 2532 e1 = intOp ( tv, e1, e2 );
2424 case TOKmul: 2533 else
2425 nextToken(); 2534 {
2426 e2 = parseMultExp(); 2535 slotExp ( e1 );
2427 if (isIntExp(e1) && isIntExp(e2)) 2536 slotExp ( e2 );
2428 e1 = intOp(tv, e1, e2); 2537 e1 = Handled;
2429 else if (tryScale(e1,e2)) 2538 }
2430 e1 = Handled; 2539 continue;
2431 else 2540 case TOKmin:
2432 invalidExpression(); 2541 // Note: no support for symbol address difference
2433 continue; 2542 nextToken();
2434 case TOKdiv: 2543 e2 = parseMultExp();
2435 case TOKmod: 2544 if ( isIntExp ( e1 ) && isIntExp ( e2 ) )
2436 nextToken(); 2545 e1 = intOp ( tv, e1, e2 );
2437 e2 = parseMultExp(); 2546 else
2438 e1 = intOp(tv, e1, e2); 2547 {
2439 continue; 2548 slotExp ( e1 );
2440 default: 2549 e2 = intOp ( TOKmin, e2, NULL ); // verifies e2 is an int
2441 break; 2550 slotExp ( e2 );
2442 } 2551 e1 = Handled;
2443 break; 2552 }
2444 } 2553 continue;
2445 return e1; 2554 default:
2446 } 2555 break;
2447 2556 }
2448 Expression * parseBrExp() { 2557 break;
2449 // %% check (why is bracket lower precends..) 2558 }
2450 // 3+4[eax] -> 3 + (4 [EAX]) .. 2559 return e1;
2451 2560 }
2452 // only one bracked allowed, so this doesn't quite handle 2561
2453 // the spec'd syntax 2562 bool tryScale ( Expression * e1, Expression * e2 )
2454 Expression * e; 2563 {
2455 2564 Expression * et;
2456 if (token->value == TOKlbracket) 2565 if ( isIntExp ( e1 ) && isRegExp ( e2 ) )
2457 e = Handled; 2566 {
2458 else 2567 et = e1;
2459 e = parseUnaExp(); 2568 e1 = e2;
2460 2569 e2 = et;
2461 // DMD allows multiple bracket expressions. 2570 goto do_scale;
2462 while (token->value == TOKlbracket) { 2571 }
2463 nextToken(); 2572 else if ( isRegExp ( e1 ) && isIntExp ( e2 ) )
2464 2573 {
2465 operand->inBracket = operand->hasBracket = 1; 2574 do_scale:
2466 slotExp(parseAsmExp()); 2575 if ( ! operand->inBracket )
2467 operand->inBracket = 0; 2576 {
2468 2577 invalidExpression(); // maybe should allow, e.g. DS:EBX+EAX*4
2469 if (token->value == TOKrbracket) 2578 }
2470 nextToken(); 2579
2471 else 2580 if ( operand->scale || operand->indexReg != Reg_Invalid )
2472 stmt->error("missing ']'"); 2581 {
2473 } 2582 invalidExpression();
2474 2583 return true;
2475 return e; 2584 }
2476 } 2585
2477 2586 operand->indexReg = ( Reg ) e1->toInteger();
2478 PtrType isPtrType(Token * tok) { 2587 operand->scale = e2->toInteger();
2479 switch (tok->value) { 2588 switch ( operand->scale )
2480 case TOKint8: return Byte_Ptr; 2589 {
2481 case TOKint16: return Short_Ptr; 2590 case 1:
2482 case TOKint32: return Int_Ptr; 2591 case 2:
2483 // 'long ptr' isn't accepted? 2592 case 4:
2484 case TOKfloat32: return Float_Ptr; 2593 case 8:
2485 case TOKfloat64: return Double_Ptr; 2594 // ok; do nothing
2486 case TOKfloat80: return Extended_Ptr; 2595 break;
2487 case TOKidentifier: 2596 default:
2488 for (int i = 0; i < N_PtrNames; i++) 2597 stmt->error ( "invalid index register scale '%d'", operand->scale );
2489 if (tok->ident == ptrTypeIdentTable[i]) 2598 return true;
2490 return ptrTypeValueTable[i]; 2599 }
2491 break; 2600
2492 default: 2601 return true;
2493 break; 2602 }
2494 } 2603 return false;
2495 return Default_Ptr; 2604 }
2496 } 2605
2497 2606 Expression * parseMultExp()
2498 Expression * parseUnaExp() { 2607 {
2499 Expression * e = NULL; 2608 Expression * e1 = parseBrExp();
2500 PtrType ptr_type; 2609 Expression * e2;
2501 2610
2502 // First, check for type prefix. 2611 while ( 1 )
2503 if (token->value != TOKeof && 2612 {
2504 peekToken()->value == TOKidentifier && 2613 TOK tv = token->value;
2505 peekToken()->ident == Id::ptr) { 2614 switch ( tv )
2506 2615 {
2507 ptr_type = isPtrType(token); 2616 case TOKmul:
2508 if (ptr_type != Default_Ptr) { 2617 nextToken();
2509 if (operand->dataSize == Default_Ptr) 2618 e2 = parseMultExp();
2510 operand->dataSize = ptr_type; 2619 if ( isIntExp ( e1 ) && isIntExp ( e2 ) )
2511 else 2620 e1 = intOp ( tv, e1, e2 );
2512 stmt->error("multiple specifications of operand size"); 2621 else if ( tryScale ( e1,e2 ) )
2513 } else 2622 e1 = Handled;
2514 stmt->error("unknown operand size '%s'", token->toChars()); 2623 else
2515 nextToken(); 2624 invalidExpression();
2516 nextToken(); 2625 continue;
2517 return parseAsmExp(); 2626 case TOKdiv:
2518 } 2627 case TOKmod:
2519 2628 nextToken();
2520 TOK tv = token->value; 2629 e2 = parseMultExp();
2521 switch (tv) { 2630 e1 = intOp ( tv, e1, e2 );
2522 case TOKidentifier: 2631 continue;
2523 if (token->ident == ident_seg) { 2632 default:
2524 nextToken(); 2633 break;
2525 stmt->error("'seg' not supported"); 2634 }
2526 e = parseAsmExp(); 2635 break;
2527 } else if (token->ident == Id::offset || 2636 }
2528 token->ident == Id::offsetof) { 2637 return e1;
2529 if (token->ident == Id::offset && ! global.params.useDeprecated) 2638 }
2530 stmt->error("offset deprecated, use offsetof"); 2639
2531 nextToken(); 2640 Expression * parseBrExp()
2532 e = parseAsmExp(); 2641 {
2533 e = new AddrExp(stmt->loc, e); 2642 // %% check (why is bracket lower precends..)
2534 } else { 2643 // 3+4[eax] -> 3 + (4 [EAX]) ..
2535 // primary exp 2644
2536 break; 2645 // only one bracked allowed, so this doesn't quite handle
2537 } 2646 // the spec'd syntax
2538 return e; 2647 Expression * e;
2539 case TOKadd: 2648
2540 case TOKmin: 2649 if ( token->value == TOKlbracket )
2541 case TOKnot: 2650 e = Handled;
2542 case TOKtilde: 2651 else
2543 nextToken(); 2652 e = parseUnaExp();
2544 e = parseUnaExp(); 2653
2545 return intOp(tv, e, NULL); 2654 // DMD allows multiple bracket expressions.
2546 default: 2655 while ( token->value == TOKlbracket )
2547 // primary exp 2656 {
2548 break; 2657 nextToken();
2549 } 2658
2550 return parsePrimaryExp(); 2659 operand->inBracket = operand->hasBracket = 1;
2551 } 2660 slotExp ( parseAsmExp() );
2552 2661 operand->inBracket = 0;
2553 Expression * parsePrimaryExp() { 2662
2554 Expression * e; 2663 if ( token->value == TOKrbracket )
2555 Identifier * ident = NULL; 2664 nextToken();
2556 2665 else
2557 switch (token->value) { 2666 stmt->error ( "missing ']'" );
2558 case TOKint32v: 2667 }
2559 case TOKuns32v: 2668
2560 case TOKint64v: 2669 return e;
2561 case TOKuns64v: 2670 }
2562 // semantic here? 2671
2563 // %% for tok64 really should use 64bit type 2672 PtrType isPtrType ( Token * tok )
2564 e = new IntegerExp(stmt->loc, token->uns64value, Type::tint32); 2673 {
2565 nextToken(); 2674 switch ( tok->value )
2566 break; 2675 {
2567 case TOKfloat32v: 2676 case TOKint8: return Byte_Ptr;
2568 case TOKfloat64v: 2677 case TOKint16: return Short_Ptr;
2569 case TOKfloat80v: 2678 case TOKint32: return Int_Ptr;
2570 // %% need different types? 2679 // 'long ptr' isn't accepted?
2571 e = new RealExp(stmt->loc, token->float80value, Type::tfloat80); 2680 case TOKfloat32: return Float_Ptr;
2572 nextToken(); 2681 case TOKfloat64: return Double_Ptr;
2573 break; 2682 case TOKfloat80: return Extended_Ptr;
2574 case TOKidentifier: 2683 case TOKidentifier:
2575 { 2684 for ( int i = 0; i < N_PtrNames; i++ )
2576 ident = token->ident; 2685 if ( tok->ident == ptrTypeIdentTable[i] )
2577 nextToken(); 2686 return ptrTypeValueTable[i];
2578 2687 break;
2579 if (ident == Id::__LOCAL_SIZE) { 2688 default:
2580 return new IdentifierExp(stmt->loc, ident); 2689 break;
2581 } else if (ident == Id::__dollar) { 2690 }
2582 do_dollar: 2691 return Default_Ptr;
2583 return new IdentifierExp(stmt->loc, ident); 2692 }
2584 } else { 2693
2585 e = new IdentifierExp(stmt->loc, ident); 2694 Expression * parseUnaExp()
2586 } 2695 {
2587 2696 Expression * e = NULL;
2588 // If this is more than one component ref, it gets complicated: *(&Field + n) 2697 PtrType ptr_type;
2589 // maybe just do one step at a time.. 2698
2590 // simple case is Type.f -> VarDecl(field) 2699 // First, check for type prefix.
2591 // actually, DMD only supports on level... 2700 if ( token->value != TOKeof &&
2592 // X.y+Y.z[EBX] is supported, tho.. 2701 peekToken()->value == TOKidentifier &&
2593 // %% doesn't handle properties (check%%) 2702 peekToken()->ident == Id::ptr )
2594 while (token->value == TOKdot) { 2703 {
2595 nextToken(); 2704
2596 if (token->value == TOKidentifier) { 2705 ptr_type = isPtrType ( token );
2597 e = new DotIdExp(stmt->loc, e, token->ident); 2706 if ( ptr_type != Default_Ptr )
2598 nextToken(); 2707 {
2599 } else { 2708 if ( operand->dataSize == Default_Ptr )
2600 stmt->error("expected identifier"); 2709 operand->dataSize = ptr_type;
2601 return Handled; 2710 else
2602 } 2711 stmt->error ( "multiple specifications of operand size" );
2603 } 2712 }
2604 2713 else
2605 // check for reg first then dotexp is an error? 2714 stmt->error ( "unknown operand size '%s'", token->toChars() );
2606 if (e->op == TOKidentifier) { 2715 nextToken();
2607 for (int i = 0; i < N_Regs; i++) { 2716 nextToken();
2608 if (ident == regInfo[i].ident) { 2717 return parseAsmExp();
2609 if ( (Reg) i == Reg_ST && token->value == TOKlparen) { 2718 }
2610 nextToken(); 2719
2611 switch (token->value) { 2720 TOK tv = token->value;
2612 case TOKint32v: case TOKuns32v: 2721 switch ( tv )
2613 case TOKint64v: case TOKuns64v: 2722 {
2614 if (token->uns64value < 8) 2723 case TOKidentifier:
2615 e = newRegExp( (Reg) (Reg_ST + token->uns64value) ); 2724 if ( token->ident == ident_seg )
2616 else { 2725 {
2617 stmt->error("invalid floating point register index"); 2726 nextToken();
2618 e = Handled; 2727 stmt->error ( "'seg' not supported" );
2619 } 2728 e = parseAsmExp();
2620 nextToken(); 2729 }
2621 if (token->value == TOKrparen) 2730 else if ( token->ident == Id::offset ||
2622 nextToken(); 2731 token->ident == Id::offsetof )
2623 else 2732 {
2624 stmt->error("expected ')'"); 2733 if ( token->ident == Id::offset && ! global.params.useDeprecated )
2625 return e; 2734 stmt->error ( "offset deprecated, use offsetof" );
2626 default: 2735 nextToken();
2627 break; 2736 e = parseAsmExp();
2628 } 2737 e = new AddrExp ( stmt->loc, e );
2629 invalidExpression(); 2738 }
2630 return Handled; 2739 else
2631 } else if (token->value == TOKcolon) { 2740 {
2632 nextToken(); 2741 // primary exp
2633 if (operand->segmentPrefix != Reg_Invalid) 2742 break;
2634 stmt->error("too many segment prefixes"); 2743 }
2635 else if (i >= Reg_CS && i <= Reg_GS) 2744 return e;
2636 operand->segmentPrefix = (Reg) i; 2745 case TOKadd:
2637 else 2746 case TOKmin:
2638 stmt->error("'%s' is not a segment register", ident->string); 2747 case TOKnot:
2639 return parseAsmExp(); 2748 case TOKtilde:
2640 } else { 2749 nextToken();
2641 return newRegExp( (Reg) i ); 2750 e = parseUnaExp();
2642 } 2751 return intOp ( tv, e, NULL );
2643 } 2752 default:
2644 } 2753 // primary exp
2645 } 2754 break;
2646 2755 }
2647 if (opTakesLabel()/*opInfo->takesLabel()*/ && e->op == TOKidentifier) { 2756 return parsePrimaryExp();
2648 // DMD uses labels secondarily to other symbols, so check 2757 }
2649 // if IdentifierExp::semantic won't find anything. 2758
2650 Dsymbol *scopesym; 2759 Expression * parsePrimaryExp()
2651 2760 {
2652 if ( ! sc->search(stmt->loc, ident, & scopesym) ) 2761 Expression * e;
2653 return new DsymbolExp(stmt->loc, 2762 Identifier * ident = NULL;
2654 sc->func->searchLabel( ident )); 2763
2655 } 2764 switch ( token->value )
2656 2765 {
2657 e = e->semantic(sc); 2766 case TOKint32v:
2658 2767 case TOKuns32v:
2659 // Special case for floating point constant declarations. 2768 case TOKint64v:
2660 if (e->op == TOKfloat64) { 2769 case TOKuns64v:
2661 Dsymbol * sym = sc->search(stmt->loc, ident, NULL); 2770 // semantic here?
2662 if ( sym ) { 2771 // %% for tok64 really should use 64bit type
2663 VarDeclaration *v = sym->isVarDeclaration(); 2772 e = new IntegerExp ( stmt->loc, token->uns64value, Type::tint32 );
2664 if ( v ) { 2773 nextToken();
2665 Expression *ve = new VarExp(stmt->loc, v); 2774 break;
2666 ve->type = e->type; 2775 case TOKfloat32v:
2667 e = ve; 2776 case TOKfloat64v:
2668 } 2777 case TOKfloat80v:
2669 } 2778 // %% need different types?
2670 } 2779 e = new RealExp ( stmt->loc, token->float80value, Type::tfloat80 );
2671 return e; 2780 nextToken();
2672 } 2781 break;
2673 break; 2782 case TOKidentifier:
2674 case TOKdollar: 2783 {
2675 nextToken(); 2784 ident = token->ident;
2676 ident = Id::__dollar; 2785 nextToken();
2677 goto do_dollar; 2786
2678 break; 2787 if ( ident == Id::__LOCAL_SIZE )
2679 default: 2788 {
2680 invalidExpression(); 2789 return new IdentifierExp ( stmt->loc, ident );
2681 return Handled; 2790 }
2682 } 2791 else if ( ident == Id::__dollar )
2683 return e; 2792 {
2684 } 2793 do_dollar:
2685 2794 return new IdentifierExp ( stmt->loc, ident );
2686 void doAlign() { 2795 }
2687 // .align bits vs. bytes... 2796 else
2688 // apparently a.out platforms use bits instead of bytes... 2797 {
2689 2798 e = new IdentifierExp ( stmt->loc, ident );
2690 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2' 2799 }
2691 // GAS is padding with NOPs last time I checked. 2800
2692 Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret); 2801 // If this is more than one component ref, it gets complicated: *(&Field + n)
2693 uinteger_t align = e->toUInteger(); 2802 // maybe just do one step at a time..
2694 2803 // simple case is Type.f -> VarDecl(field)
2695 if ((align & (align - 1)) == 0) { 2804 // actually, DMD only supports on level...
2696 //FIXME: This printf is not portable. The use of `align` varies from system to system; 2805 // X.y+Y.z[EBX] is supported, tho..
2697 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary 2806 // %% doesn't handle properties (check%%)
2698 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 2807 while ( token->value == TOKdot )
2699 insnTemplate->printf(".balign\t%u", (unsigned) align); 2808 {
2809 nextToken();
2810 if ( token->value == TOKidentifier )
2811 {
2812 e = new DotIdExp ( stmt->loc, e, token->ident );
2813 nextToken();
2814 }
2815 else
2816 {
2817 stmt->error ( "expected identifier" );
2818 return Handled;
2819 }
2820 }
2821
2822 // check for reg first then dotexp is an error?
2823 if ( e->op == TOKidentifier )
2824 {
2825 for ( int i = 0; i < N_Regs; i++ )
2826 {
2827 if ( ident == regInfo[i].ident )
2828 {
2829 if ( ( Reg ) i == Reg_ST && token->value == TOKlparen )
2830 {
2831 nextToken();
2832 switch ( token->value )
2833 {
2834 case TOKint32v: case TOKuns32v:
2835 case TOKint64v: case TOKuns64v:
2836 if ( token->uns64value < 8 )
2837 e = newRegExp ( ( Reg ) ( Reg_ST + token->uns64value ) );
2838 else
2839 {
2840 stmt->error ( "invalid floating point register index" );
2841 e = Handled;
2842 }
2843 nextToken();
2844 if ( token->value == TOKrparen )
2845 nextToken();
2846 else
2847 stmt->error ( "expected ')'" );
2848 return e;
2849 default:
2850 break;
2851 }
2852 invalidExpression();
2853 return Handled;
2854 }
2855 else if ( token->value == TOKcolon )
2856 {
2857 nextToken();
2858 if ( operand->segmentPrefix != Reg_Invalid )
2859 stmt->error ( "too many segment prefixes" );
2860 else if ( i >= Reg_CS && i <= Reg_GS )
2861 operand->segmentPrefix = ( Reg ) i;
2862 else
2863 stmt->error ( "'%s' is not a segment register", ident->string );
2864 return parseAsmExp();
2865 }
2866 else
2867 {
2868 return newRegExp ( ( Reg ) i );
2869 }
2870 }
2871 }
2872 }
2873
2874 if ( opTakesLabel() /*opInfo->takesLabel()*/ && e->op == TOKidentifier )
2875 {
2876 // DMD uses labels secondarily to other symbols, so check
2877 // if IdentifierExp::semantic won't find anything.
2878 Dsymbol *scopesym;
2879
2880 if ( ! sc->search ( stmt->loc, ident, & scopesym ) )
2881 return new DsymbolExp ( stmt->loc,
2882 sc->func->searchLabel ( ident ) );
2883 }
2884
2885 e = e->semantic ( sc );
2886
2887 // Special case for floating point constant declarations.
2888 if ( e->op == TOKfloat64 )
2889 {
2890 Dsymbol * sym = sc->search ( stmt->loc, ident, NULL );
2891 if ( sym )
2892 {
2893 VarDeclaration *v = sym->isVarDeclaration();
2894 if ( v )
2895 {
2896 Expression *ve = new VarExp ( stmt->loc, v );
2897 ve->type = e->type;
2898 e = ve;
2899 }
2900 }
2901 }
2902 return e;
2903 }
2904 break;
2905 case TOKdollar:
2906 nextToken();
2907 ident = Id::__dollar;
2908 goto do_dollar;
2909 break;
2910 default:
2911 invalidExpression();
2912 return Handled;
2913 }
2914 return e;
2915 }
2916
2917 void doAlign()
2918 {
2919 // .align bits vs. bytes...
2920 // apparently a.out platforms use bits instead of bytes...
2921
2922 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2'
2923 // GAS is padding with NOPs last time I checked.
2924 Expression * e = parseAsmExp()->optimize ( WANTvalue | WANTinterpret );
2925 uinteger_t align = e->toUInteger();
2926
2927 if ( ( align & ( align - 1 ) ) == 0 )
2928 {
2929 //FIXME: This printf is not portable. The use of `align` varies from system to system;
2930 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary
2931 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
2932 insnTemplate->printf ( ".balign\t%u", ( unsigned ) align );
2700 #else 2933 #else
2701 insnTemplate->printf(".align\t%u", (unsigned) align); 2934 insnTemplate->printf ( ".align\t%u", ( unsigned ) align );
2702 #endif 2935 #endif
2703 } else { 2936 }
2704 stmt->error("alignment must be a power of 2, not %u", (unsigned) align); 2937 else
2705 } 2938 {
2706 2939 stmt->error ( "alignment must be a power of 2, not %u", ( unsigned ) align );
2707 setAsmCode(); 2940 }
2708 } 2941
2709 2942 setAsmCode();
2710 void doEven() { 2943 }
2711 // .align for GAS is in bits, others probably use bytes.. 2944
2712 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 2945 void doEven()
2713 insnTemplate->writestring((char *) ".align\t2"); 2946 {
2947 // .align for GAS is in bits, others probably use bytes..
2948 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
2949 insnTemplate->writestring ( ( char * ) ".align\t2" );
2714 #else 2950 #else
2715 insnTemplate->writestring((char *) ".align\t2"); 2951 insnTemplate->writestring ( ( char * ) ".align\t2" );
2716 #endif 2952 #endif
2717 setAsmCode(); 2953 setAsmCode();
2718 } 2954 }
2719 2955
2720 void doNaked() { 2956 void doNaked()
2721 // %% can we assume sc->func != 0? 2957 {
2722 sc->func->naked = 1; 2958 // %% can we assume sc->func != 0?
2723 } 2959 sc->func->naked = 1;
2724 2960 }
2725 void doData() { 2961
2726 static const char * directives[] = { ".byte", ".short", ".long", ".long", 2962 void doData()
2727 "", "", "" }; 2963 {
2964 static const char * directives[] = { ".byte", ".short", ".long", ".long",
2965 "", "", ""
2966 };
2728 // FIXME 2967 // FIXME
2729 /* 2968 /*
2730 machine_mode mode; 2969 machine_mode mode;
2731 2970
2732 insnTemplate->writestring((char*) directives[op - Op_db]); 2971 insnTemplate->writestring((char*) directives[op - Op_db]);
2733 insnTemplate->writebyte(' '); 2972 insnTemplate->writebyte(' ');
2734 2973
2735 do { 2974 do {
2736 // DMD is pretty strict here, not even constant expressions are allowed.. 2975 // DMD is pretty strict here, not even constant expressions are allowed..
2737 switch (op) { 2976 switch (op) {
2738 case Op_db: 2977 case Op_db:
2739 case Op_ds: 2978 case Op_ds:
2740 case Op_di: 2979 case Op_di:
2741 case Op_dl: 2980 case Op_dl:
2742 if (token->value == TOKint32v || token->value == TOKuns32v || 2981 if (token->value == TOKint32v || token->value == TOKuns32v ||
2743 token->value == TOKint64v || token->value == TOKuns64v) { 2982 token->value == TOKint64v || token->value == TOKuns64v) {
2744 // As per usual with GNU, assume at least 32-bit host 2983 // As per usual with GNU, assume at least 32-bit host
2745 if (op != Op_dl) 2984 if (op != Op_dl)
2746 insnTemplate->printf("%u", (d_uns32) token->uns64value); 2985 insnTemplate->printf("%u", (d_uns32) token->uns64value);
2747 else { 2986 else {
2748 // Output two .longS. GAS has .quad, but would have to rely on 'L' format .. 2987 // Output two .longS. GAS has .quad, but would have to rely on 'L' format ..
2749 // just need to use HOST_WIDE_INT_PRINT_DEC 2988 // just need to use HOST_WIDE_INT_PRINT_DEC
2750 insnTemplate->printf("%u,%u", 2989 insnTemplate->printf("%u,%u",
2751 (d_uns32) token->uns64value, (d_uns32) (token->uns64value >> 32)); 2990 (d_uns32) token->uns64value, (d_uns32) (token->uns64value >> 32));
2752 } 2991 }
2753 } else { 2992 } else {
2754 stmt->error("expected integer constant"); 2993 stmt->error("expected integer constant");
2755 } 2994 }
2756 break; 2995 break;
2757 case Op_df: 2996 case Op_df:
2758 mode = SFmode; 2997 mode = SFmode;
2759 goto do_float; 2998 goto do_float;
2760 case Op_dd: 2999 case Op_dd:
2761 mode = DFmode; 3000 mode = DFmode;
2762 goto do_float; 3001 goto do_float;
2763 case Op_de: 3002 case Op_de:
2764 #ifndef TARGET_80387 3003 #ifndef TARGET_80387
2765 #define XFmode TFmode 3004 #define XFmode TFmode
2766 #endif 3005 #endif
2767 mode = XFmode; // not TFmode 3006 mode = XFmode; // not TFmode
2768 // drop through 3007 // drop through
2769 do_float: 3008 do_float:
2770 if (token->value == TOKfloat32v || token->value == TOKfloat64v || 3009 if (token->value == TOKfloat32v || token->value == TOKfloat64v ||
2771 token->value == TOKfloat80v) { 3010 token->value == TOKfloat80v) {
2772 long words[3]; 3011 long words[3];
2773 real_to_target(words, & token->float80value.rv(), mode); 3012 real_to_target(words, & token->float80value.rv(), mode);
2774 // don't use directives..., just use .long like GCC 3013 // don't use directives..., just use .long like GCC
2775 insnTemplate->printf(".long\t%u", words[0]); 3014 insnTemplate->printf(".long\t%u", words[0]);
2776 if (mode != SFmode) 3015 if (mode != SFmode)
2777 insnTemplate->printf(",%u", words[1]); 3016 insnTemplate->printf(",%u", words[1]);
2778 // DMD outputs 10 bytes, so we need to switch to .short here 3017 // DMD outputs 10 bytes, so we need to switch to .short here
2779 if (mode == XFmode) 3018 if (mode == XFmode)
2780 insnTemplate->printf("\n\t.short\t%u", words[2]); 3019 insnTemplate->printf("\n\t.short\t%u", words[2]);
2781 } else { 3020 } else {
2782 stmt->error("expected float constant"); 3021 stmt->error("expected float constant");
2783 } 3022 }
2784 break; 3023 break;
2785 default: 3024 default:
2786 abort(); 3025 abort();
2787 } 3026 }
2788 3027
2789 nextToken(); 3028 nextToken();
2790 if (token->value == TOKcomma) { 3029 if (token->value == TOKcomma) {
2791 insnTemplate->writebyte(','); 3030 insnTemplate->writebyte(',');
2792 nextToken(); 3031 nextToken();
2793 } else if (token->value == TOKeof) { 3032 } else if (token->value == TOKeof) {
2794 break; 3033 break;
2795 } else { 3034 } else {
2796 stmt->error("expected comma"); 3035 stmt->error("expected comma");
2797 } 3036 }
2798 } while (1); 3037 } while (1);
2799 3038
2800 setAsmCode();*/ 3039 setAsmCode();*/
2801 } 3040 }
2802 }; 3041 };
2803 3042
2804 #if D_GCC_VER < 40 3043 #if D_GCC_VER < 40
2805 // struct rtx was modified for c++; this macro from rtl.h needs to 3044 // struct rtx was modified for c++; this macro from rtl.h needs to
2806 // be modified accordingly. 3045 // be modified accordingly.
2807 #undef XEXP 3046 #undef XEXP
2808 #define XEXP(RTX, N) (RTL_CHECK2 (RTX, N, 'e', 'u').rt_rtx) 3047 #define XEXP(RTX, N) (RTL_CHECK2 (RTX, N, 'e', 'u').rt_rtx)
2809 #endif 3048 #endif
2810 3049
2811 // FIXME 3050 // FIXME
2812 #define HOST_WIDE_INT long 3051 #define HOST_WIDE_INT long
2813 bool getFrameRelativeValue(LLValue* decl, HOST_WIDE_INT * result) 3052 bool getFrameRelativeValue ( LLValue* decl, HOST_WIDE_INT * result )
2814 { 3053 {
2815 assert(0); 3054 assert ( 0 );
2816 // FIXME 3055 // FIXME
2817 // // Using this instead of DECL_RTL for struct args seems like a 3056 // // Using this instead of DECL_RTL for struct args seems like a
2818 // // good way to get hit by a truck because it may not agree with 3057 // // good way to get hit by a truck because it may not agree with
2819 // // non-asm access, but asm code wouldn't know what GCC does anyway. */ 3058 // // non-asm access, but asm code wouldn't know what GCC does anyway. */
2820 // rtx r = DECL_INCOMING_RTL(decl); 3059 // rtx r = DECL_INCOMING_RTL(decl);
2821 // rtx e1, e2; 3060 // rtx e1, e2;
2822 // 3061 //
2823 // // Local variables don't have DECL_INCOMING_RTL 3062 // // Local variables don't have DECL_INCOMING_RTL
2824 // if (r == NULL_RTX) 3063 // if (r == NULL_RTX)
2825 // r = DECL_RTL(decl); 3064 // r = DECL_RTL(decl);
2826 // 3065 //
2827 // if (r != NULL_RTX && GET_CODE(r) == MEM /* && r->frame_related */ ) { 3066 // if (r != NULL_RTX && GET_CODE(r) == MEM /* && r->frame_related */ ) {
2828 // r = XEXP(r, 0); 3067 // r = XEXP(r, 0);
2829 // if (GET_CODE(r) == PLUS) { 3068 // if (GET_CODE(r) == PLUS) {
2830 // e1 = XEXP(r, 0); 3069 // e1 = XEXP(r, 0);
2831 // e2 = XEXP(r, 1); 3070 // e2 = XEXP(r, 1);
2832 // if (e1 == virtual_incoming_args_rtx && GET_CODE(e2) == CONST_INT) { 3071 // if (e1 == virtual_incoming_args_rtx && GET_CODE(e2) == CONST_INT) {
2833 // *result = INTVAL(e2) + 8; // %% 8 is 32-bit specific... 3072 // *result = INTVAL(e2) + 8; // %% 8 is 32-bit specific...
2834 // return true; 3073 // return true;
2835 // } else if (e1 == virtual_stack_vars_rtx && GET_CODE(e2) == CONST_INT) { 3074 // } else if (e1 == virtual_stack_vars_rtx && GET_CODE(e2) == CONST_INT) {
2836 // *result = INTVAL(e2); // %% 8 is 32-bit specific... 3075 // *result = INTVAL(e2); // %% 8 is 32-bit specific...
2837 // return true; 3076 // return true;
2838 // } 3077 // }
2839 // } else if (r == virtual_incoming_args_rtx) { 3078 // } else if (r == virtual_incoming_args_rtx) {
2840 // *result = 8; 3079 // *result = 8;
2841 // return true; // %% same as above 3080 // return true; // %% same as above
2842 // } 3081 // }
2843 // // shouldn't have virtual_stack_vars_rtx by itself 3082 // // shouldn't have virtual_stack_vars_rtx by itself
2844 // } 3083 // }
2845 // 3084 //
2846 return false; 3085 return false;
3086 }
3087
3088
3089 struct AsmParser : public AsmParserCommon
3090 {
3091 virtual void run ( Scope* sc, AsmStatement* asmst )
3092 {
3093 AsmProcessor ap ( sc, asmst );
3094 ap.run();
3095 }
3096
3097 virtual std::string getRegName ( int i )
3098 {
3099 return regInfo[i].gccName;
3100 }
3101 };
3102
2847 } 3103 }
2848
2849
2850 struct AsmParser : public AsmParserCommon
2851 {
2852 virtual void run(Scope* sc, AsmStatement* asmst) {
2853 AsmProcessor ap(sc, asmst);
2854 ap.run();
2855 }
2856
2857 virtual std::string getRegName(int i) {
2858 return regInfo[i].gccName;
2859 }
2860 };
2861
2862 }