comparison gen/d-asm-i386.h @ 219:761c8352f494 trunk

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