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