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