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