comparison gen/asm-x86-64.h @ 756:a58784e0f035

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