Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/gen/asm-x86-64.h

Revision 1634:9cc791423e20, 116.2 kB (checked in by Kelly Wilson <wilsonk cpsc.ucalgary.ca>, 2 years ago)

Fix typo for iretq

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