13 Reg_ST1
, Reg_ST2
, Reg_ST3
, Reg_ST4
, Reg_ST5
, Reg_ST6
, Reg_ST7
,
14 Reg_MM0
, Reg_MM1
, Reg_MM2
, Reg_MM3
, Reg_MM4
, Reg_MM5
, Reg_MM6
, Reg_MM7
,
15 Reg_XMM0
, Reg_XMM1
, Reg_XMM2
, Reg_XMM3
, Reg_XMM4
, Reg_XMM5
, Reg_XMM6
, Reg_XMM7
,
16 // will need 64-bit rax,etc. eventually
25 Reg_AX
, Reg_BX
, Reg_CX
, Reg_DX
, Reg_SI
, Reg_DI
, Reg_BP
, Reg_SP
,
26 Reg_AL
, Reg_AH
, Reg_BL
, Reg_BH
, Reg_CL
, Reg_CH
, Reg_DL
, Reg_DH
,
27 Reg_CR0
, Reg_CR2
, Reg_CR3
, Reg_CR4
,
28 Reg_DR0
, Reg_DR1
, Reg_DR2
, Reg_DR3
, Reg_DR6
, Reg_DR7
,
29 Reg_TR3
, Reg_TR4
, Reg_TR5
, Reg_TR6
, Reg_TR7
32 static const int N_Regs
= /*gp*/ 8 + /*fp*/ 8 + /*mmx*/ 8 + /*sse*/ 8 +
33 /*seg*/ 6 + /*16bit*/ 8 + /*8bit*/ 8 + /*sys*/ 4+6+5 + /*flags*/ + 1;
37 tree gccName
; // GAS will take upper case, but GCC won't (needed for the clobber list)
40 char baseReg
; // %% todo: Reg, Reg_XX
42 { "EAX", NULL_TREE
, NULL
, 4, Reg_EAX
},
43 { "EBX", NULL_TREE
, NULL
, 4, Reg_EBX
},
44 { "ECX", NULL_TREE
, NULL
, 4, Reg_ECX
},
45 { "EDX", NULL_TREE
, NULL
, 4, Reg_EDX
},
46 { "ESI", NULL_TREE
, NULL
, 4, Reg_ESI
},
47 { "EDI", NULL_TREE
, NULL
, 4, Reg_EDI
},
48 { "EBP", NULL_TREE
, NULL
, 4, Reg_EBP
},
49 { "ESP", NULL_TREE
, NULL
, 4, Reg_ESP
},
50 { "ST", NULL_TREE
, NULL
, 10, Reg_ST
},
51 { "ST(1)", NULL_TREE
, NULL
,10, Reg_ST1
},
52 { "ST(2)", NULL_TREE
, NULL
,10, Reg_ST2
},
53 { "ST(3)", NULL_TREE
, NULL
,10, Reg_ST3
},
54 { "ST(4)", NULL_TREE
, NULL
,10, Reg_ST4
},
55 { "ST(5)", NULL_TREE
, NULL
,10, Reg_ST5
},
56 { "ST(6)", NULL_TREE
, NULL
,10, Reg_ST6
},
57 { "ST(7)", NULL_TREE
, NULL
,10, Reg_ST7
},
58 { "MM0", NULL_TREE
, NULL
, 8, Reg_MM0
},
59 { "MM1", NULL_TREE
, NULL
, 8, Reg_MM1
},
60 { "MM2", NULL_TREE
, NULL
, 8, Reg_MM2
},
61 { "MM3", NULL_TREE
, NULL
, 8, Reg_MM3
},
62 { "MM4", NULL_TREE
, NULL
, 8, Reg_MM4
},
63 { "MM5", NULL_TREE
, NULL
, 8, Reg_MM5
},
64 { "MM6", NULL_TREE
, NULL
, 8, Reg_MM6
},
65 { "MM7", NULL_TREE
, NULL
, 8, Reg_MM7
},
66 { "XMM0", NULL_TREE
, NULL
, 16, Reg_XMM0
},
67 { "XMM1", NULL_TREE
, NULL
, 16, Reg_XMM1
},
68 { "XMM2", NULL_TREE
, NULL
, 16, Reg_XMM2
},
69 { "XMM3", NULL_TREE
, NULL
, 16, Reg_XMM3
},
70 { "XMM4", NULL_TREE
, NULL
, 16, Reg_XMM4
},
71 { "XMM5", NULL_TREE
, NULL
, 16, Reg_XMM5
},
72 { "XMM6", NULL_TREE
, NULL
, 16, Reg_XMM6
},
73 { "XMM7", NULL_TREE
, NULL
, 16, Reg_XMM7
},
74 { "FLAGS", NULL_TREE
, NULL
, 0, Reg_EFLAGS
}, // the gcc name is "flags"; not used in assembler input
75 { "CS", NULL_TREE
, NULL
, 2, -1 },
76 { "DS", NULL_TREE
, NULL
, 2, -1 },
77 { "SS", NULL_TREE
, NULL
, 2, -1 },
78 { "ES", NULL_TREE
, NULL
, 2, -1 },
79 { "FS", NULL_TREE
, NULL
, 2, -1 },
80 { "GS", NULL_TREE
, NULL
, 2, -1 },
81 { "AX", NULL_TREE
, NULL
, 2, Reg_EAX
},
82 { "BX", NULL_TREE
, NULL
, 2, Reg_EBX
},
83 { "CX", NULL_TREE
, NULL
, 2, Reg_ECX
},
84 { "DX", NULL_TREE
, NULL
, 2, Reg_EDX
},
85 { "SI", NULL_TREE
, NULL
, 2, Reg_ESI
},
86 { "DI", NULL_TREE
, NULL
, 2, Reg_EDI
},
87 { "BP", NULL_TREE
, NULL
, 2, Reg_EBP
},
88 { "SP", NULL_TREE
, NULL
, 2, Reg_ESP
},
89 { "AL", NULL_TREE
, NULL
, 1, Reg_EAX
},
90 { "AH", NULL_TREE
, NULL
, 1, Reg_EAX
},
91 { "BL", NULL_TREE
, NULL
, 1, Reg_EBX
},
92 { "BH", NULL_TREE
, NULL
, 1, Reg_EBX
},
93 { "CL", NULL_TREE
, NULL
, 1, Reg_ECX
},
94 { "CH", NULL_TREE
, NULL
, 1, Reg_ECX
},
95 { "DL", NULL_TREE
, NULL
, 1, Reg_EDX
},
96 { "DH", NULL_TREE
, NULL
, 1, Reg_EDX
},
97 { "CR0", NULL_TREE
, NULL
, 0, -1 },
98 { "CR2", NULL_TREE
, NULL
, 0, -1 },
99 { "CR3", NULL_TREE
, NULL
, 0, -1 },
100 { "CR4", NULL_TREE
, NULL
, 0, -1 },
101 { "DR0", NULL_TREE
, NULL
, 0, -1 },
102 { "DR1", NULL_TREE
, NULL
, 0, -1 },
103 { "DR2", NULL_TREE
, NULL
, 0, -1 },
104 { "DR3", NULL_TREE
, NULL
, 0, -1 },
105 { "DR6", NULL_TREE
, NULL
, 0, -1 },
106 { "DR7", NULL_TREE
, NULL
, 0, -1 },
107 { "TR3", NULL_TREE
, NULL
, 0, -1 },
108 { "TR4", NULL_TREE
, NULL
, 0, -1 },
109 { "TR5", NULL_TREE
, NULL
, 0, -1 },
110 { "TR6", NULL_TREE
, NULL
, 0, -1 },
111 { "TR7", NULL_TREE
, NULL
, 0, -1 }
117 Word_Types
, // same as Int_Types, but byte is not allowed
120 Byte_NoType
, // byte only, but no type suffix
133 Clb_DXAX_Mask
= 0x03,
140 Clb_SP
= 0x80 // Doesn't actually let GCC know the frame pointer is modified
143 // "^ +/..\([A-Za-z_0-9]+\).*" -> " \1,"
285 OprC_Port
= 13, // DX or imm
286 OprC_AX
= 14, // AL,AX,EAX
287 OprC_DX
= 15, // only DX
290 OprC_Shift
= 18, // imm or CL
292 Opr_ClassMask
= 0x1f,
304 typedef unsigned char Opr
;
310 implicitClobbers
: 8,
316 return operands[0] & Opr_Label;
320 unsigned nOperands() {
323 else if (!operands
[1])
325 else if (!operands
[2])
341 } Alternate_Mnemonics
;
343 static const char * alternateMnemonics
[N_AltMn
] = {
360 #define ssem OprC_SSE_Mem
362 #define mmxm OprC_MMX_Mem
364 #define rw OprC_RWord
366 #define port OprC_Port
369 #define shft OprC_Shift
373 //#define L Opr_Label
376 static AsmOpInfo asmOpInfo
[N_AsmOpInfo
] = {
378 /* Op_Adjust */ { 0,0,0, 0, Clb_EAX
/*just AX*/ },
379 /* Op_Dst */ { D
|mr
, 0, 0, 1 },
380 /* Op_Upd */ { U
|mr
, 0, 0, 1 },
381 /* Op_DstW */ { D
|mr
, 0, 0, Word_Types
},
382 /* Op_DstF */ { D
|mr
, 0, 0, 1, Clb_Flags
},
383 /* Op_UpdF */ { U
|mr
, 0, 0, 1, Clb_Flags
},
384 /* Op_DstSrc */ { D
|mr
, mri
, 0,/**/1 },
385 /* Op_DstSrcF */ { D
|mr
, mri
, 0,/**/1, Clb_Flags
},
386 /* Op_UpdSrcF */ { U
|mr
, mri
, 0,/**/1, Clb_Flags
},
387 /* Op_DstSrcFW */ { D
|mr
, mri
, 0,/**/Word_Types
, Clb_Flags
},
388 /* Op_UpdSrcFW */ { U
|mr
, mri
, 0,/**/Word_Types
, Clb_Flags
},
389 /* Op_DstSrcSSE */ { U
|sse
, ssem
, 0 }, // some may not be update %%
390 /* Op_DstSrcMMX */ { U
|mmx
, mmxm
, 0 }, // some may not be update %%
391 /* Op_DstSrcImmS*/ { U
|sse
, ssem
, N
|imm
}, // some may not be update %%
392 /* Op_DstSrcImmM*/ { U
|mmx
, mmxm
, N
|imm
}, // some may not be update %%
393 /* Op_UpdSrcShft*/ { U
|mr
, reg
, N
|shft
, 1, Clb_Flags
}, // 16/32 only
394 /* Op_DstSrcNT */ { D
|mr
, mr
, 0, 0 }, // used for movd .. operands can be rm32,sse,mmx
395 /* Op_UpdSrcNT */ { U
|mr
, mr
, 0, 0 }, // used for movd .. operands can be rm32,sse,mmx
396 /* Op_DstMemNT */ { D
|mem
, 0, 0 },
397 /* Op_DstRMBNT */ { D
|mr
, 0, 0, Byte_NoType
},
398 /* Op_DstRMWNT */ { D
|mr
, 0, 0 },
399 /* Op_UpdUpd */ { U
|mr
,U
|mr
, 0,/**/1 },
400 /* Op_UpdUpdF */ { U
|mr
,U
|mr
, 0,/**/1, Clb_Flags
},
401 /* Op_Src */ { mri
, 0, 0, 1 },
402 /* Op_SrcRMWNT */ { mr
, 0, 0, 0 },
403 /* Op_SrcW */ { mri
, 0, 0, Word_Types
},
404 /* Op_SrcImm */ { imm
},
405 /* Op_Src_DXAXF */ { mr
, 0, 0, 1, Clb_SizeDXAX
|Clb_Flags
},
406 /* Op_SrcMemNT */ { mem
, 0, 0 },
407 /* Op_SrcMemNTF */ { mem
, 0, 0, 0, Clb_Flags
},
408 /* Op_SrcSrc */ { mr
, mri
, 0, 1 },
409 /* Op_SrcSrcF */ { mr
, mri
, 0, 1, Clb_Flags
},
410 /* Op_SrcSrcFW */ { mr
, mri
, 0, Word_Types
, Clb_Flags
},
411 /* Op_SrcSrcSSEF*/ { sse
, ssem
, 0, 0, Clb_Flags
},
412 /* Op_SrcSrcMMX */ { mmx
, mmx
, 0, },
413 /* Op_Shift */ { D
|mr
,N
|shft
, 0,/**/1, Clb_Flags
},
414 /* Op_Branch */ { mri
},
415 /* Op_CBranch */ { imm
},
416 /* Op_0 */ { 0,0,0 },
417 /* Op_0_AX */ { 0,0,0, 0, Clb_SizeAX
},
418 /* Op_0_DXAX */ { 0,0,0, 0, Clb_SizeDXAX
}, // but for cwd/cdq -- how do know the size..
419 /* Op_Loop */ { imm
, 0, 0, 0, Clb_CX
},
420 /* Op_Flags */ { 0,0,0, 0, Clb_Flags
},
421 /* Op_F0_ST */ { 0,0,0, 0, Clb_ST
},
422 /* Op_F0_P */ { 0,0,0, 0, Clb_ST
}, // push, pops, etc. not sure how to inform gcc..
423 /* Op_Fs_P */ { mem
, 0, 0, 0, Clb_ST
}, // "
424 /* Op_Fis */ { mem
, 0, 0, FPInt_Types
}, // only 16bit and 32bit, DMD defaults to 16bit
425 /* Op_Fis_ST */ { mem
, 0, 0, FPInt_Types
, Clb_ST
}, // "
426 /* Op_Fis_P */ { mem
, 0, 0, FPInt_Types
, Clb_ST
}, // push and pop, fild so also 64 bit
427 /* Op_Fid */ { D
|mem
, 0, 0, FPInt_Types
}, // only 16bit and 32bit, DMD defaults to 16bit
428 /* Op_Fid_P */ { D
|mem
, 0, 0, FPInt_Types
, Clb_ST
}, // push and pop, fild so also 64 bit
429 /* 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
430 /* Op_FfdR */ { D
|rfp
, 0, 0 },
431 /* Op_Ffd_P */ { D
|mfp
, 0, 0, FP_Types
, Clb_ST
, Next_Form
, Op_FfdR_P
, }, // pop, fld so also 80 bit, "
432 /* Op_FfdR_P */ { D
|rfp
, 0, 0, 0, Clb_ST
},
433 /* Op_Fd_P */ { D
|mem
, 0, 0, 0, Clb_ST
}, // "
434 /* Op_FdST */ { D
|rfp
, 0, 0 },
435 /* Op_FMath */ { mfp
, 0, 0, FP_Types
, Clb_ST
, Next_Form
, Op_FdSTiSTi
}, // and only single or double prec
436 /* Op_FdSTiSTi */ { D
|rfp
, rfp
, 0, },
437 /* Op_FPMath */ { D
|rfp
, rfp
, 0, 0, Clb_ST
, Next_Form
, Op_F0_P
}, // pops
438 /* Op_FCmp */ { mfp
, 0, 0, FP_Types
, 0, Next_Form
, Op_FCmp1
}, // DMD defaults to float ptr
439 /* Op_FCmp1 */ { rfp
, 0, 0, 0, 0, Next_Form
, Op_0
},
440 /* Op_FCmpP */ { mfp
, 0, 0, FP_Types
, 0, Next_Form
, Op_FCmpP1
}, // pops
441 /* Op_FCmpP1 */ { rfp
, 0, 0, 0, 0, Next_Form
, Op_F0_P
}, // pops
442 /* Op_FCmpFlg */ { rfp
, rfp
, 0, 0, Clb_Flags
},
443 /* Op_FCmpFlgP */ { rfp
, rfp
, 0, 0, Clb_Flags
}, // pops
444 /* Op_fld */ { mfp
, 0, 0, FP_Types
, Clb_ST
, Next_Form
, Op_fldR
},
445 /* Op_fldR */ { rfp
, 0, 0, 0, Clb_ST
},
446 /* 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
447 /* Op_fxch1 */ { D
|rfp
, 0, 0, 0, Clb_ST
, Next_Form
, Op_fxch0
},
448 /* Op_fxch0 */ { 0, 0, 0, 0, Clb_ST
}, // Also clobbers ST(1)
449 /* Op_SizedStack*/ { 0, 0, 0, 0, Clb_SP
}, // type suffix special case
450 /* Op_bound */ { mr
, mri
, 0, Word_Types
}, // operands *not* reversed for gas
451 /* Op_bswap */ { D
|r32
},
452 /* Op_cmps */ { mem
, mem
, 0, 1, Clb_DI
|Clb_SI
|Clb_Flags
},
453 /* Op_cmpsd */ { 0, 0, 0, 0, Clb_DI
|Clb_SI
|Clb_Flags
, Next_Form
, Op_DstSrcImmS
},
454 /* Op_cmpsX */ { 0, 0, 0, 0, Clb_DI
|Clb_SI
|Clb_Flags
},
455 /* Op_cmpxchg8b */ { D
|mem
/*64*/,0,0, 0, Clb_SizeDXAX
/*32*/|Clb_Flags
, Out_Mnemonic
, Mn_cmpxchg8b
},
456 /* Op_cmpxchg */ { D
|mr
, reg
, 0, 1, Clb_SizeAX
|Clb_Flags
},
457 /* Op_cpuid */ { 0,0,0 }, // Clobbers eax, ebx, ecx, and edx. Handled specially below.
458 /* Op_enter */ { imm
, imm
}, // operands *not* reversed for gas, %% inform gcc of EBP clobber?,
459 /* Op_fdisi */ { 0,0,0, 0, 0, Out_Mnemonic
, Mn_fdisi
},
460 /* Op_feni */ { 0,0,0, 0, 0, Out_Mnemonic
, Mn_feni
},
461 /* Op_fsetpm */ { 0,0,0, 0, 0, Out_Mnemonic
, Mn_fsetpm
},
462 /* Op_fXstsw */ { D
|mr
, 0, 0, }, // ax is the only allowed register
463 /* Op_imul */ { D
|reg
, mr
, imm
, 1, Clb_Flags
, Next_Form
, Op_imul2
}, // 16/32 only
464 /* Op_imul2 */ { D
|reg
, mri
, 0, 1, Clb_Flags
, Next_Form
, Op_imul1
}, // 16/32 only
465 /* Op_imul1 */ { mr
, 0, 0, 1, Clb_Flags
|Clb_SizeDXAX
},
466 /* Op_in */ { D
|ax
,N
|port
,0, 1 },
467 /* Op_ins */ { mem
,N
|dx
, 0, 1, Clb_DI
}, // can't override ES segment for this one
468 /* Op_insX */ { 0, 0, 0, 0, Clb_DI
}, // output segment overrides %% needs work
469 /* Op_iret */ { 0,0,0, 0, 0, Out_Mnemonic
, Mn_iretw
},
470 /* Op_iretd */ { 0,0,0, 0, 0, Out_Mnemonic
, Mn_iret
},
471 /* Op_lods */ { mem
, 0, 0, 1, Clb_SI
},
472 /* Op_lodsX */ { 0, 0, 0, 0, Clb_SI
},
473 /* Op_movs */ { mem
, mem
, 0, 1, Clb_DI
|Clb_SI
}, // only src/DS can be overridden
474 /* Op_movsd */ { 0, 0, 0, 0, Clb_DI
|Clb_SI
, Next_Form
, Op_DstSrcSSE
}, // %% gas doesn't accept movsd .. has to movsl
475 /* Op_movsX */ { 0, 0, 0, 0, Clb_DI
|Clb_SI
},
476 /* Op_movsx */ { D
|reg
, mr
, 0, 1 }, // type suffix is special case
477 /* Op_movzx */ { D
|reg
, mr
, 0, 1 }, // type suffix is special case
478 /* Op_mul */ { U
|ax
, mr
, 0, 1, Clb_SizeDXAX
|Clb_Flags
, Next_Form
, Op_Src_DXAXF
},
479 /* Op_out */ { N
|port
,ax
, 0, 1 },
480 /* Op_outs */ { N
|dx
, mem
, 0, 1, Clb_SI
},
481 /* Op_outsX */ { 0, 0, 0, 0, Clb_SI
},
482 /* Op_push */ { mri
, 0, 0, Word_Types
, Clb_SP
}, // would be Op_SrcW, but DMD defaults to 32-bit for immediate form
483 /* Op_ret */ { imm
, 0, 0, 0, 0, Next_Form
, Op_0
},
484 /* Op_retf */ { 0, 0, 0, 0, 0, Out_Mnemonic
, Mn_lret
},
485 /* Op_scas */ { mem
, 0, 0, 1, Clb_DI
|Clb_Flags
},
486 /* Op_scasX */ { 0, 0, 0, 0, Clb_DI
|Clb_Flags
},
487 /* Op_stos */ { mem
, 0, 0, 1, Clb_DI
},
488 /* Op_stosX */ { 0, 0, 0, 0, Clb_DI
},
489 /* Op_xlat */ { mem
, 0, 0, 0, Clb_SizeAX
}
491 /// * Op_arpl */ { D|mr, reg }, // 16 only -> DstSrc
492 /// * Op_bsX */ { rw, mrw, 0, 1, Clb_Flags },//->srcsrcf
493 /// * Op_bt */ { mrw, riw, 0, 1, Clb_Flags },//->srcsrcf
494 /// * Op_btX */ { D|mrw, riw, 0, 1, Clb_Flags },//->dstsrcf .. immediate does not contribute to size
495 /// * Op_cmovCC */ { D|rw, mrw, 0, 1 } // ->dstsrc
521 const char * inMnemonic
;
525 /* Some opcodes which have data size restrictions, but we don't check
527 cmov, l<segreg> ?, lea, lsl, shld
529 todo: push <immediate> is always the 32-bit form, even tho push <mem> is 16-bit
532 static AsmOpEnt opData
[] = {
533 { "aaa", Op_Adjust
},
534 { "aad", Op_Adjust
},
535 { "aam", Op_Adjust
},
536 { "aas", Op_Adjust
},
537 { "adc", Op_UpdSrcF
},
538 { "add", Op_UpdSrcF
},
539 { "addpd", Op_DstSrcSSE
},
540 { "addps", Op_DstSrcSSE
},
541 { "addsd", Op_DstSrcSSE
},
542 { "addss", Op_DstSrcSSE
},
543 { "addsubpd", Op_DstSrcSSE
},
544 { "addsubps", Op_DstSrcSSE
},
545 { "align", Op_Align
},
546 { "and", Op_UpdSrcF
},
547 { "andnpd", Op_DstSrcSSE
},
548 { "andnps", Op_DstSrcSSE
},
549 { "andpd", Op_DstSrcSSE
},
550 { "andps", Op_DstSrcSSE
},
551 { "arpl", Op_UpdSrcNT
},
552 { "bound", Op_bound
},
553 { "bsf", Op_SrcSrcFW
},
554 { "bsr", Op_SrcSrcFW
},
555 { "bswap", Op_bswap
},
556 { "bt", Op_SrcSrcFW
},
557 { "btc", Op_UpdSrcFW
},
558 { "btr", Op_UpdSrcFW
},
559 { "bts", Op_UpdSrcFW
},
560 { "call", Op_Branch
},
562 { "cdq", Op_0_DXAX
},
565 { "clflush",Op_SrcMemNT
},
569 { "cmova", Op_DstSrc
},
570 { "cmovae", Op_DstSrc
},
571 { "cmovb", Op_DstSrc
},
572 { "cmovbe", Op_DstSrc
},
573 { "cmovc", Op_DstSrc
},
574 { "cmove", Op_DstSrc
},
575 { "cmovg", Op_DstSrc
},
576 { "cmovge", Op_DstSrc
},
577 { "cmovl", Op_DstSrc
},
578 { "cmovle", Op_DstSrc
},
579 { "cmovna", Op_DstSrc
},
580 { "cmovnae",Op_DstSrc
},
581 { "cmovnb", Op_DstSrc
},
582 { "cmovnbe",Op_DstSrc
},
583 { "cmovnc", Op_DstSrc
},
584 { "cmovne", Op_DstSrc
},
585 { "cmovng", Op_DstSrc
},
586 { "cmovnge",Op_DstSrc
},
587 { "cmovnl", Op_DstSrc
},
588 { "cmovnle",Op_DstSrc
},
589 { "cmovno", Op_DstSrc
},
590 { "cmovnp", Op_DstSrc
},
591 { "cmovns", Op_DstSrc
},
592 { "cmovnz", Op_DstSrc
},
593 { "cmovo", Op_DstSrc
},
594 { "cmovp", Op_DstSrc
},
595 { "cmovpe", Op_DstSrc
},
596 { "cmovpo", Op_DstSrc
},
597 { "cmovs", Op_DstSrc
},
598 { "cmovz", Op_DstSrc
},
599 { "cmp", Op_SrcSrcF
},
600 { "cmppd", Op_DstSrcImmS
},
601 { "cmpps", Op_DstSrcImmS
},
603 { "cmpsb", Op_cmpsX
},
604 { "cmpsd", Op_cmpsd
}, // string cmp, and SSE cmp
605 { "cmpss", Op_DstSrcImmS
},
606 { "cmpsw", Op_cmpsX
},
607 { "cmpxch8b", Op_cmpxchg8b
}, // %% DMD opcode typo?
608 { "cmpxchg", Op_cmpxchg
},
609 { "comisd", Op_SrcSrcSSEF
},
610 { "comiss", Op_SrcSrcSSEF
},
611 { "cpuid", Op_cpuid
},
612 { "cvtdq2pd", Op_DstSrcSSE
},
613 { "cvtdq2ps", Op_DstSrcSSE
},
614 { "cvtpd2dq", Op_DstSrcSSE
},
615 { "cvtpd2pi", Op_DstSrcSSE
},
616 { "cvtpd2ps", Op_DstSrcSSE
},
617 { "cvtpi2pd", Op_DstSrcSSE
},
618 { "cvtpi2ps", Op_DstSrcSSE
},
619 { "cvtps2dq", Op_DstSrcSSE
},
620 { "cvtps2pd", Op_DstSrcSSE
},
621 { "cvtps2pi", Op_DstSrcSSE
},
622 { "cvtsd2si", Op_DstSrcSSE
},
623 { "cvtsd2ss", Op_DstSrcSSE
},
624 { "cvtsi2sd", Op_DstSrcSSE
},
625 { "cvtsi2ss", Op_DstSrcSSE
},
626 { "cvtss2sd", Op_DstSrcSSE
},
627 { "cvtss2si", Op_DstSrcSSE
},
628 { "cvttpd2dq", Op_DstSrcSSE
},
629 { "cvttpd2pi", Op_DstSrcSSE
},
630 { "cvttps2dq", Op_DstSrcSSE
},
631 { "cvttps2pi", Op_DstSrcSSE
},
632 { "cvttsd2si", Op_DstSrcSSE
},
633 { "cvttss2si", Op_DstSrcSSE
},
634 { "cwd", Op_0_DXAX
},
636 //{ "da", Op_ },// dunno what this is -- takes labels?
637 { "daa", Op_Adjust
},
638 { "das", Op_Adjust
},
645 { "div", Op_Src_DXAXF
},
646 { "divpd", Op_DstSrcSSE
},
647 { "divps", Op_DstSrcSSE
},
648 { "divsd", Op_DstSrcSSE
},
649 { "divss", Op_DstSrcSSE
},
655 { "emms", Op_0
}, // clobber all mmx/fp?
656 { "enter", Op_enter
},
658 { "f2xm1", Op_F0_ST
}, // %% most of these are update...
659 { "fabs", Op_F0_ST
},
660 { "fadd", Op_FMath
},
661 { "faddp", Op_FPMath
},
663 { "fbstp", Op_Fd_P
},
664 { "fchs", Op_F0_ST
},
666 { "fcmovb", Op_FdSTiSTi
}, // but only ST(0) can be the destination -- should be FdST0STi
667 { "fcmovbe", Op_FdSTiSTi
},
668 { "fcmove", Op_FdSTiSTi
},
669 { "fcmovnb", Op_FdSTiSTi
},
670 { "fcmovnbe", Op_FdSTiSTi
},
671 { "fcmovne", Op_FdSTiSTi
},
672 { "fcmovnu", Op_FdSTiSTi
},
673 { "fcmovu", Op_FdSTiSTi
},
675 { "fcomi", Op_FCmpFlg
},
676 { "fcomip", Op_FCmpFlgP
},
677 { "fcomp", Op_FCmpP
},
678 { "fcompp", Op_F0_P
}, // pops twice
679 { "fcos", Op_F0_ST
},
680 { "fdecstp",Op_F0_P
}, // changes stack
681 { "fdisi", Op_fdisi
},
682 { "fdiv", Op_FMath
},
683 { "fdivp", Op_FPMath
},
684 { "fdivr", Op_FMath
},
685 { "fdivrp", Op_FPMath
},
687 { "ffree", Op_FdST
},
688 { "fiadd", Op_Fis_ST
},
690 { "ficomp", Op_Fis_P
},
691 { "fidiv", Op_Fis_ST
},
692 { "fidivr", Op_Fis_ST
},
693 { "fild", Op_Fis_P
},
694 { "fimul", Op_Fis_ST
},
695 { "fincstp",Op_F0_P
},
696 { "finit", Op_F0_P
},
697 { "fist", Op_Fid
}, // only 16,32bit
698 { "fistp", Op_Fid_P
},
699 { "fisttp", Op_Fid_P
},
700 { "fisub", Op_Fis_ST
},
701 { "fisubr", Op_Fis_ST
},
704 { "fldcw", Op_SrcMemNT
},
705 { "fldenv", Op_SrcMemNT
},
706 { "fldl2e", Op_F0_P
},
707 { "fldl2t", Op_F0_P
},
708 { "fldlg2", Op_F0_P
},
709 { "fldln2", Op_F0_P
},
710 { "fldpi", Op_F0_P
},
712 { "fmul", Op_FMath
},
713 { "fmulp", Op_FPMath
},
715 { "fndisi", Op_fdisi
}, // ??
716 { "fneni", Op_feni
}, // ??
719 { "fnsave", Op_DstMemNT
},
720 { "fnstcw", Op_DstMemNT
},
721 { "fnstenv",Op_DstMemNT
},
722 { "fnstsw", Op_fXstsw
},
723 { "fpatan", Op_F0_P
}, // pop and modify new ST
724 { "fprem", Op_F0_ST
},
725 { "fprem1", Op_F0_ST
},
726 { "fptan", Op_F0_P
}, // modify ST and push 1.0
727 { "frndint",Op_F0_ST
},
728 { "frstor", Op_SrcMemNT
}, // but clobbers everything
729 { "fsave", Op_DstMemNT
},
730 { "fscale", Op_F0_ST
},
731 { "fsetpm", Op_fsetpm
},
732 { "fsin", Op_F0_ST
},
733 { "fsincos",Op_F0_P
},
734 { "fsqrt", Op_F0_ST
},
736 { "fstcw", Op_DstMemNT
},
737 { "fstenv", Op_DstMemNT
},
738 { "fstp", Op_Ffd_P
},
739 { "fstsw", Op_fXstsw
},
740 { "fsub", Op_FMath
},
741 { "fsubp", Op_FPMath
},
742 { "fsubr", Op_FMath
},
743 { "fsubrp", Op_FPMath
},
745 { "fucom", Op_FCmp
},
746 { "fucomi", Op_FCmpFlg
},
747 { "fucomip",Op_FCmpFlgP
},
748 { "fucomp", Op_FCmpP
},
749 { "fucompp",Op_F0_P
}, // pops twice
753 { "fxrstor",Op_SrcMemNT
}, // clobbers FP,MMX,SSE
754 { "fxsave", Op_DstMemNT
},
755 { "fxtract",Op_F0_P
}, // pushes
756 { "fyl2x", Op_F0_P
}, // pops
757 { "fyl2xp1",Op_F0_P
}, // pops
758 { "haddpd", Op_DstSrcSSE
},
759 { "haddps", Op_DstSrcSSE
},
761 { "hsubpd", Op_DstSrcSSE
},
762 { "hsubps", Op_DstSrcSSE
},
763 { "idiv", Op_Src_DXAXF
},
771 { "int", Op_SrcImm
},
774 { "invlpg", Op_SrcMemNT
},
776 { "iretd", Op_iretd
},
777 { "ja", Op_CBranch
},
778 { "jae", Op_CBranch
},
779 { "jb", Op_CBranch
},
780 { "jbe", Op_CBranch
},
781 { "jc", Op_CBranch
},
782 { "jcxz", Op_CBranch
},
783 { "je", Op_CBranch
},
784 { "jecxz", Op_CBranch
},
785 { "jg", Op_CBranch
},
786 { "jge", Op_CBranch
},
787 { "jl", Op_CBranch
},
788 { "jle", Op_CBranch
},
789 { "jmp", Op_Branch
},
790 { "jna", Op_CBranch
},
791 { "jnae", Op_CBranch
},
792 { "jnb", Op_CBranch
},
793 { "jnbe", Op_CBranch
},
794 { "jnc", Op_CBranch
},
795 { "jne", Op_CBranch
},
796 { "jng", Op_CBranch
},
797 { "jnge", Op_CBranch
},
798 { "jnl", Op_CBranch
},
799 { "jnle", Op_CBranch
},
800 { "jno", Op_CBranch
},
801 { "jnp", Op_CBranch
},
802 { "jns", Op_CBranch
},
803 { "jnz", Op_CBranch
},
804 { "jo", Op_CBranch
},
805 { "jp", Op_CBranch
},
806 { "jpe", Op_CBranch
},
807 { "jpo", Op_CBranch
},
808 { "js", Op_CBranch
},
809 { "jz", Op_CBranch
},
811 { "lar", Op_DstSrcFW
}, // reg dest only
812 { "lddqu", Op_DstSrcSSE
},
813 { "ldmxcsr", Op_SrcMemNT
},
814 { "lds", Op_DstSrc
}, // reg dest only
815 { "lea", Op_DstSrc
}, // "
816 { "leave", Op_0
}, // EBP,ESP clobbers
817 { "les", Op_DstSrc
},
819 { "lfs", Op_DstSrc
},
820 { "lgdt", Op_SrcMemNT
},
821 { "lgs", Op_DstSrc
},
822 { "lidt", Op_SrcMemNT
},
823 { "lldt", Op_SrcRMWNT
},
824 { "lmsw", Op_SrcRMWNT
},
827 { "lodsb", Op_lodsX
},
828 { "lodsd", Op_lodsX
},
829 { "lodsw", Op_lodsX
},
831 { "loope", Op_Loop
},
832 { "loopne",Op_Loop
},
833 { "loopnz",Op_Loop
},
834 { "loopz", Op_Loop
},
835 { "lsl", Op_DstSrcFW
}, // reg dest only
836 { "lss", Op_DstSrc
},
837 { "ltr", Op_DstMemNT
},
838 { "maskmovdqu", Op_SrcSrcMMX
}, // writes to [edi]
839 { "maskmovq", Op_SrcSrcMMX
},
840 { "maxpd", Op_DstSrcSSE
},
841 { "maxps", Op_DstSrcSSE
},
842 { "maxsd", Op_DstSrcSSE
},
843 { "maxss", Op_DstSrcSSE
},
845 { "minpd", Op_DstSrcSSE
},
846 { "minps", Op_DstSrcSSE
},
847 { "minsd", Op_DstSrcSSE
},
848 { "minss", Op_DstSrcSSE
},
850 { "mov", Op_DstSrc
},
851 { "movapd", Op_DstSrcSSE
},
852 { "movaps", Op_DstSrcSSE
},
853 { "movd", Op_DstSrcNT
}, // also mmx and sse
854 { "movddup", Op_DstSrcSSE
},
855 { "movdq2q", Op_DstSrcNT
}, // mmx/sse
856 { "movdqa", Op_DstSrcSSE
},
857 { "movdqu", Op_DstSrcSSE
},
858 { "movhlps", Op_DstSrcSSE
},
859 { "movhpd", Op_DstSrcSSE
},
860 { "movhps", Op_DstSrcSSE
},
861 { "movlhps", Op_DstSrcSSE
},
862 { "movlpd", Op_DstSrcSSE
},
863 { "movlps", Op_DstSrcSSE
},
864 { "movmskpd",Op_DstSrcSSE
},
865 { "movmskps",Op_DstSrcSSE
},
866 { "movntdq", Op_DstSrcNT
}, // limited to sse, but mem dest
867 { "movnti", Op_DstSrcNT
}, // limited to gpr, but mem dest
868 { "movntpd", Op_DstSrcNT
}, // limited to sse, but mem dest
869 { "movntps", Op_DstSrcNT
}, // limited to sse, but mem dest
870 { "movntq", Op_DstSrcNT
}, // limited to mmx, but mem dest
871 { "movq", Op_DstSrcNT
}, // limited to sse and mmx
872 { "movq2dq", Op_DstSrcNT
}, // limited to sse <- mmx regs
874 { "movsb", Op_movsX
},
875 { "movsd", Op_movsd
},
876 { "movshdup", Op_DstSrcSSE
},
877 { "movsldup", Op_DstSrcSSE
},
878 { "movss", Op_DstSrcSSE
},
879 { "movsw", Op_movsX
},
880 { "movsx", Op_movsx
}, // word-only, reg dest
881 { "movupd",Op_DstSrcSSE
},
882 { "movups",Op_DstSrcSSE
},
883 { "movzx", Op_movzx
},
885 { "mulpd", Op_DstSrcSSE
},
886 { "mulps", Op_DstSrcSSE
},
887 { "mulsd", Op_DstSrcSSE
},
888 { "mulss", Op_DstSrcSSE
},
890 { "naked", Op_Naked
},
894 { "or", Op_UpdSrcF
},
895 { "orpd", Op_DstSrcSSE
},
896 { "orps", Op_DstSrcSSE
},
899 { "outsb", Op_outsX
},
900 { "outsd", Op_outsX
},
901 { "outsw", Op_outsX
},
902 { "packssdw", Op_DstSrcMMX
}, // %% also SSE
903 { "packsswb", Op_DstSrcMMX
},
904 { "packuswb", Op_DstSrcMMX
},
905 { "paddb", Op_DstSrcMMX
},
906 { "paddd", Op_DstSrcMMX
},
907 { "paddq", Op_DstSrcMMX
},
908 { "paddsb", Op_DstSrcMMX
},
909 { "paddsw", Op_DstSrcMMX
},
910 { "paddusb", Op_DstSrcMMX
},
911 { "paddusw", Op_DstSrcMMX
},
912 { "paddw", Op_DstSrcMMX
},
913 { "pand", Op_DstSrcMMX
},
914 { "pandn", Op_DstSrcMMX
},
915 { "pavgb", Op_DstSrcMMX
},
916 { "pavgw", Op_DstSrcMMX
},
917 { "pcmpeqb", Op_DstSrcMMX
},
918 { "pcmpeqd", Op_DstSrcMMX
},
919 { "pcmpeqw", Op_DstSrcMMX
},
920 { "pcmpgtb", Op_DstSrcMMX
},
921 { "pcmpgtd", Op_DstSrcMMX
},
922 { "pcmpgtw", Op_DstSrcMMX
},
923 { "pextrw", Op_DstSrcImmM
}, // gpr32 dest
924 { "pinsrw", Op_DstSrcImmM
}, // gpr32(16), mem16 src, sse too
925 { "pmaddwd", Op_DstSrcMMX
},
926 { "pmaxsw", Op_DstSrcMMX
},
927 { "pmaxub", Op_DstSrcMMX
},
928 { "pminsw", Op_DstSrcMMX
},
929 { "pminub", Op_DstSrcMMX
},
930 { "pmovmskb", Op_DstSrcMMX
},
931 { "pmulhuw", Op_DstSrcMMX
},
932 { "pmulhw", Op_DstSrcMMX
},
933 { "pmullw", Op_DstSrcMMX
},
934 { "pmuludq", Op_DstSrcMMX
}, // also sse
936 { "popa", Op_SizedStack
}, // For intel this is always 16-bit
937 { "popad", Op_SizedStack
}, // GAS doesn't accept 'popad' -- these clobber everything, but supposedly it would be used to preserve clobbered regs
938 { "popf", Op_SizedStack
}, // rewrite the insn with a special case
939 { "popfd", Op_SizedStack
},
940 { "por", Op_DstSrcMMX
},
941 { "prefetchnta", Op_SrcMemNT
},
942 { "prefetcht0", Op_SrcMemNT
},
943 { "prefetcht1", Op_SrcMemNT
},
944 { "prefetcht2", Op_SrcMemNT
},
945 { "psadbw", Op_DstSrcMMX
},
946 { "pshufd", Op_DstSrcImmM
},
947 { "pshufhw", Op_DstSrcImmM
},
948 { "pshuflw", Op_DstSrcImmM
},
949 { "pshufw", Op_DstSrcImmM
},
950 { "pslld", Op_DstSrcMMX
}, // immediate operands...
951 { "pslldq", Op_DstSrcMMX
},
952 { "psllq", Op_DstSrcMMX
},
953 { "psllw", Op_DstSrcMMX
},
954 { "psrad", Op_DstSrcMMX
},
955 { "psraw", Op_DstSrcMMX
},
956 { "psrld", Op_DstSrcMMX
},
957 { "psrldq", Op_DstSrcMMX
},
958 { "psrlq", Op_DstSrcMMX
},
959 { "psrlw", Op_DstSrcMMX
},
960 { "psubb", Op_DstSrcMMX
},
961 { "psubd", Op_DstSrcMMX
},
962 { "psubq", Op_DstSrcMMX
},
963 { "psubsb", Op_DstSrcMMX
},
964 { "psubsw", Op_DstSrcMMX
},
965 { "psubusb", Op_DstSrcMMX
},
966 { "psubusw", Op_DstSrcMMX
},
967 { "psubw", Op_DstSrcMMX
},
968 { "punpckhbw", Op_DstSrcMMX
},
969 { "punpckhdq", Op_DstSrcMMX
},
970 { "punpckhqdq",Op_DstSrcMMX
},
971 { "punpckhwd", Op_DstSrcMMX
},
972 { "punpcklbw", Op_DstSrcMMX
},
973 { "punpckldq", Op_DstSrcMMX
},
974 { "punpcklqdq",Op_DstSrcMMX
},
975 { "punpcklwd", Op_DstSrcMMX
},
977 { "pusha", Op_SizedStack
},
978 { "pushad", Op_SizedStack
},
979 { "pushf", Op_SizedStack
},
980 { "pushfd", Op_SizedStack
},
981 { "pxor", Op_DstSrcMMX
},
982 { "rcl", Op_Shift
}, // limited src operands -- change to shift
983 { "rcpps", Op_DstSrcSSE
},
984 { "rcpss", Op_DstSrcSSE
},
986 { "rdmsr", Op_0_DXAX
},
987 { "rdpmc", Op_0_DXAX
},
988 { "rdtsc", Op_0_DXAX
},
999 { "rsqrtps", Op_DstSrcSSE
},
1000 { "rsqrtss", Op_DstSrcSSE
},
1001 { "sahf", Op_Flags
},
1002 { "sal", Op_Shift
},
1003 { "sar", Op_Shift
},
1004 { "sbb", Op_UpdSrcF
},
1005 { "scas", Op_scas
},
1006 { "scasb", Op_scasX
},
1007 { "scasd", Op_scasX
},
1008 { "scasw", Op_scasX
},
1009 { "seta", Op_DstRMBNT
}, // also gpr8
1010 { "setae", Op_DstRMBNT
},
1011 { "setb", Op_DstRMBNT
},
1012 { "setbe", Op_DstRMBNT
},
1013 { "setc", Op_DstRMBNT
},
1014 { "sete", Op_DstRMBNT
},
1015 { "setg", Op_DstRMBNT
},
1016 { "setge", Op_DstRMBNT
},
1017 { "setl", Op_DstRMBNT
},
1018 { "setle", Op_DstRMBNT
},
1019 { "setna", Op_DstRMBNT
},
1020 { "setnae", Op_DstRMBNT
},
1021 { "setnb", Op_DstRMBNT
},
1022 { "setnbe", Op_DstRMBNT
},
1023 { "setnc", Op_DstRMBNT
},
1024 { "setne", Op_DstRMBNT
},
1025 { "setng", Op_DstRMBNT
},
1026 { "setnge", Op_DstRMBNT
},
1027 { "setnl", Op_DstRMBNT
},
1028 { "setnle", Op_DstRMBNT
},
1029 { "setno", Op_DstRMBNT
},
1030 { "setnp", Op_DstRMBNT
},
1031 { "setns", Op_DstRMBNT
},
1032 { "setnz", Op_DstRMBNT
},
1033 { "seto", Op_DstRMBNT
},
1034 { "setp", Op_DstRMBNT
},
1035 { "setpe", Op_DstRMBNT
},
1036 { "setpo", Op_DstRMBNT
},
1037 { "sets", Op_DstRMBNT
},
1038 { "setz", Op_DstRMBNT
},
1040 { "sgdt", Op_DstMemNT
},
1041 { "shl", Op_Shift
},
1042 { "shld", Op_UpdSrcShft
},
1043 { "shr", Op_Shift
},
1044 { "shrd", Op_UpdSrcShft
},
1045 { "shufpd", Op_DstSrcImmS
},
1046 { "shufps", Op_DstSrcImmS
},
1047 { "sidt", Op_DstMemNT
},
1048 { "sldt", Op_DstRMWNT
},
1049 { "smsw", Op_DstRMWNT
},
1050 { "sqrtpd", Op_DstSrcSSE
},
1051 { "sqrtps", Op_DstSrcSSE
},
1052 { "sqrtsd", Op_DstSrcSSE
},
1053 { "sqrtss", Op_DstSrcSSE
},
1054 { "stc", Op_Flags
},
1055 { "std", Op_Flags
},
1056 { "sti", Op_Flags
},
1057 { "stmxcsr",Op_DstMemNT
},
1058 { "stos", Op_stos
},
1059 { "stosb", Op_stosX
},
1060 { "stosd", Op_stosX
},
1061 { "stosw", Op_stosX
},
1062 { "str", Op_DstMemNT
}, // also r16
1063 { "sub", Op_UpdSrcF
},
1064 { "subpd", Op_DstSrcSSE
},
1065 { "subps", Op_DstSrcSSE
},
1066 { "subsd", Op_DstSrcSSE
},
1067 { "subss", Op_DstSrcSSE
},
1068 { "sysenter",Op_0
},
1069 { "sysexit", Op_0
},
1070 { "test", Op_SrcSrcF
},
1071 { "ucomisd", Op_SrcSrcSSEF
},
1072 { "ucomiss", Op_SrcSrcSSEF
},
1074 { "unpckhpd", Op_DstSrcSSE
},
1075 { "unpckhps", Op_DstSrcSSE
},
1076 { "unpcklpd", Op_DstSrcSSE
},
1077 { "unpcklps", Op_DstSrcSSE
},
1078 { "verr", Op_SrcMemNTF
},
1079 { "verw", Op_SrcMemNTF
},
1083 { "xadd", Op_UpdUpdF
},
1084 { "xchg", Op_UpdUpd
},
1085 { "xlat", Op_xlat
},
1086 { "xlatb", Op_0_AX
},
1087 { "xor", Op_DstSrcF
},
1088 { "xorpd", Op_DstSrcSSE
},
1089 { "xorps", Op_DstSrcSSE
},
1106 static const int N_PtrNames
= 8;
1107 static const char * ptrTypeNameTable
[N_PtrNames
] = {
1108 "word", "dword", "qword",
1109 "float", "double", "extended",
1113 static Identifier
* ptrTypeIdentTable
[N_PtrNames
];
1114 static PtrType ptrTypeValueTable
[N_PtrNames
] = {
1115 Short_Ptr
, Int_Ptr
, QWord_Ptr
,
1116 Float_Ptr
, Double_Ptr
, Extended_Ptr
,
1127 /* kill inlining if we reference a local? */
1129 /* DMD seems to allow only one 'symbol' per operand .. include __LOCAL_SIZE */
1131 /* DMD offset usage: <parm>[<reg>] seems to always be relative to EBP+8 .. even
1136 // -- have to assume we know wheter or not to use '$'
1138 static Token eof_tok
;
1139 static Expression
* Handled
;
1140 static Identifier
* ident_seg
;
1152 sinteger_t constDisplacement
; // use to build up.. should be int constant in the end..
1153 Array symbolDisplacement
; // array of expressions or..
1160 PtrType dataSizeHint
; // DMD can use the type of a referenced variable
1163 static const unsigned Max_Operands
= 3;
1165 AsmStatement
* stmt
;
1169 OutBuffer
* insnTemplate
;
1173 Operand operands
[Max_Operands
];
1174 Identifier
* opIdent
;
1177 AsmProcessor(Scope
* sc
, AsmStatement
* stmt
)
1181 token
= stmt
->tokens
;
1182 insnTemplate
= new OutBuffer
;
1186 if ( ! regInfo
[0].ident
) {
1189 for (int i
= 0; i
< N_Regs
; i
++) {
1190 strncpy(buf
, regInfo
[i
].name
, sizeof(buf
) - 1);
1191 for (p
= buf
; *p
; p
++)
1193 regInfo
[i
].gccName
= build_string(p
- buf
, buf
);
1194 dkeep(regInfo
[i
].gccName
);
1195 if ( (i
<= Reg_ST
|| i
> Reg_ST7
) && i
!= Reg_EFLAGS
)
1196 regInfo
[i
].ident
= Lexer::idPool(regInfo
[i
].name
);
1199 for (int i
= 0; i
< N_PtrNames
; i
++)
1200 ptrTypeIdentTable
[i
] = Lexer::idPool(ptrTypeNameTable
[i
]);
1202 Handled
= new Expression(0, TOKvoid
, sizeof(Expression
));
1204 ident_seg
= Lexer::idPool("seg");
1206 eof_tok
.value
= TOKeof
;
1218 token
= token
->next
;
1223 Token
* peekToken() {
1231 if (token
->value
!= TOKeof
)
1232 stmt
->error("expected end of statement"); // %% extra at end...
1254 if (op
>= Op_db
&& op
<= Op_de
)
1261 AsmOp
parseOpcode() {
1262 static const int N_ents
= sizeof(opData
)/sizeof(AsmOpEnt
);
1264 switch (token
->value
) {
1270 opIdent
= Id::___in
;
1272 case TOKint32
: // "int"
1274 opIdent
= Id::__int
;
1278 opIdent
= Id::___out
;
1281 // search for mnemonic below
1284 stmt
->error("expected opcode");
1288 opIdent
= token
->ident
;
1289 const char * opcode
= token
->ident
->string
;
1293 // %% okay to use bsearch?
1294 int i
= 0, j
= N_ents
, k
, l
;
1297 l
= strcmp(opcode
, opData
[k
].inMnemonic
);
1299 return opData
[k
].asmOp
;
1306 stmt
->error("unknown opcode '%s'", opcode
);
1311 // need clobber information.. use information is good too...
1312 void doInstruction() {
1314 unsigned operand_i
= 0;
1316 opInfo
= & asmOpInfo
[op
];
1317 memset(operands
, 0, sizeof(operands
));
1319 while (token
->value
!= TOKeof
) {
1320 if (operand_i
< Max_Operands
) {
1321 operand
= & operands
[operand_i
];
1322 operand
->reg
= operand
->baseReg
= operand
->indexReg
=
1323 operand
->segmentPrefix
= Reg_Invalid
;
1328 stmt
->error("too many operands for instruction");
1332 if (token
->value
== TOKcomma
)
1334 else if (token
->value
!= TOKeof
) {
1336 stmt
->error("expected comma after operand");
1340 // if (operand_i < opInfo->minOperands) {
1342 // stmt->error("too few operands for instruction");
1345 if ( matchOperands(operand_i
) ) {
1346 AsmCode
* asmcode
= new AsmCode
;
1348 if (formatInstruction(operand_i
, asmcode
))
1349 stmt
->asmcode
= (code
*) asmcode
;
1354 AsmCode
* asmcode
= new AsmCode
;
1355 asmcode
->insnTemplateLen
= insnTemplate
->offset
;
1356 asmcode
->insnTemplate
= (char*) insnTemplate
->extractData();
1357 stmt
->asmcode
= (code
*) asmcode
;
1360 // note: doesn't update AsmOp op
1361 bool matchOperands(unsigned nOperands
) {
1362 bool wrong_number
= true;
1364 for (unsigned i
= 0; i
< nOperands
; i
++)
1365 classifyOperand(& operands
[i
]);
1368 if (nOperands
== opInfo
->nOperands()) {
1369 wrong_number
= false;
1370 /* Cases in which number of operands is not
1371 enough for a match: Op_FCmp/Op_FCmp1,
1372 Op_FCmpP/Op_FCmpP1 */
1373 for (unsigned i
= 0; i
< nOperands
; i
++) {
1374 Operand
* operand
= & operands
[i
];
1376 switch (opInfo
->operands
[i
] & Opr_ClassMask
) {
1377 case OprC_Mem
: // no FPMem currently
1378 if (operand
->cls
!= Opr_Mem
)
1382 if (! (operand
->reg
>= Reg_ST
&& operand
->reg
<= Reg_ST7
))
1393 if (opInfo
->linkType
== Next_Form
)
1394 opInfo
= & asmOpInfo
[ op
= (AsmOp
) opInfo
->link
];
1399 stmt
->error("wrong number of operands");
1401 stmt
->error("wrong operand types");
1405 void addOperand(const char * fmt
, AsmArgType type
, Expression
* e
, AsmCode
* asmcode
, AsmArgMode mode
= Mode_Input
) {
1406 insnTemplate
->writestring((char*) fmt
);
1407 insnTemplate
->printf("%d", asmcode
->args
.dim
);
1408 asmcode
->args
.push( new AsmArg(type
, e
, mode
) );
1411 void addLabel(unsigned n
) {
1412 // No longer taking the address of the actual label -- doesn't seem like it would help.
1415 d_format_priv_asm_label(buf
, n
);
1416 insnTemplate
->writestring(buf
);
1419 /* Determines whether the operand is a register, memory reference
1420 or immediate. Immediate addresses are currently classified as
1421 memory. This function is called before the exact instructions
1422 is known and thus, should not use opInfo. */
1423 void classifyOperand(Operand
* operand
) {
1424 operand
->cls
= classifyOperand1(operand
);
1427 OperandClass
classifyOperand1(Operand
* operand
) {
1428 bool is_localsize
= false;
1429 bool really_have_symbol
= false;
1431 if (operand
->symbolDisplacement
.dim
) {
1432 is_localsize
= isLocalSize( (Expression
*) operand
->symbolDisplacement
.data
[0] );
1433 really_have_symbol
= ! is_localsize
;
1436 if (operand
->isOffset
&& ! operand
->hasBracket
)
1437 return Opr_Immediate
;
1439 if (operand
->hasBracket
|| really_have_symbol
) { // %% redo for 'offset' function
1440 if (operand
->reg
!= Reg_Invalid
) {
1441 invalidExpression();
1448 if (operand
->reg
!= Reg_Invalid
&& operand
->constDisplacement
!= 0) {
1449 invalidExpression();
1453 if (operand
->segmentPrefix
!= Reg_Invalid
) {
1454 if (operand
->reg
!= Reg_Invalid
) {
1455 invalidExpression();
1462 if (operand
->reg
!= Reg_Invalid
&& ! operand
->hasNumber
)
1465 // should check immediate given (operand->hasNumber);
1467 if (operand
->hasNumber
|| is_localsize
) {
1468 // size determination not correct if there are symbols Opr_Immediate
1469 if (operand
->dataSize
== Default_Ptr
) {
1470 if (operand
->constDisplacement
< 0x100)
1471 operand
->dataSize
= Byte_Ptr
;
1472 else if (operand
->constDisplacement
< 0x10000)
1473 operand
->dataSize
= Short_Ptr
;
1475 operand
->dataSize
= Int_Ptr
;
1477 return Opr_Immediate
;
1481 stmt
->error("invalid operand");
1485 void writeReg(Reg reg
) {
1486 insnTemplate
->writestring((char*) "%%");
1487 insnTemplate
->write(TREE_STRING_POINTER( regInfo
[reg
].gccName
),
1488 TREE_STRING_LENGTH( regInfo
[reg
].gccName
));
1491 bool opTakesLabel() {
1502 bool getTypeChar(TypeNeeded needed
, PtrType ptrtype
, char & type_char
)
1506 return ptrtype
== Byte_Ptr
;
1508 if (ptrtype
== Byte_Ptr
)
1513 case Byte_Ptr
: type_char
= 'b'; break;
1514 case Short_Ptr
: type_char
= 'w'; break;
1515 case Int_Ptr
: type_char
= 'l'; break;
1517 // %% these may be too strict
1523 case Short_Ptr
: type_char
= 0; break;
1524 case Int_Ptr
: type_char
= 'l'; break;
1525 case QWord_Ptr
: type_char
= 'q'; break;
1532 case Float_Ptr
: type_char
= 's'; break;
1533 case Double_Ptr
: type_char
= 'l'; break;
1534 case Extended_Ptr
: type_char
= 't'; break;
1545 // also set impl clobbers
1546 bool formatInstruction(int nOperands
, AsmCode
* asmcode
) {
1548 const char *mnemonic
;
1553 insnTemplate
= new OutBuffer
;
1554 if (opInfo
->linkType
== Out_Mnemonic
)
1555 mnemonic
= alternateMnemonics
[opInfo
->link
];
1557 mnemonic
= opIdent
->string
;
1559 if (opInfo
->needsType
) {
1560 PtrType exact_type
= Default_Ptr
;
1561 PtrType min_type
= Default_Ptr
;
1562 PtrType hint_type
= Default_Ptr
;
1564 /* Default types: This attempts to match the observed behavior of DMD */
1565 switch (opInfo
->needsType
) {
1566 case Int_Types
: min_type
= Byte_Ptr
; break;
1567 case Word_Types
: min_type
= Short_Ptr
; break;
1569 if (op
== Op_Fis_ST
) // integer math instructions
1571 else // compare, load, store
1572 min_type
= Short_Ptr
;
1574 case FP_Types
: min_type
= Float_Ptr
; break;
1576 if (op
== Op_push
&& operands
[0].cls
== Opr_Immediate
)
1579 for (int i
= 0; i
< nOperands
; i
++) {
1580 if (hint_type
== Default_Ptr
&&
1581 ! (opInfo
->operands
[i
] & Opr_NoType
))
1582 hint_type
= operands
[i
].dataSizeHint
;
1584 if ((opInfo
->operands
[i
] & Opr_NoType
) ||
1585 operands
[i
].dataSize
== Default_Ptr
)
1587 if (operands
[i
].cls
== Opr_Immediate
) {
1588 min_type
= operands
[i
].dataSize
> min_type
?
1589 operands
[i
].dataSize
: min_type
;
1591 exact_type
= operands
[i
].dataSize
; // could check for conflicting types
1597 if (exact_type
== Default_Ptr
) {
1598 type_ok
= getTypeChar((TypeNeeded
) opInfo
->needsType
, hint_type
, type_char
);
1600 type_ok
= getTypeChar((TypeNeeded
) opInfo
->needsType
, min_type
, type_char
);
1602 type_ok
= getTypeChar((TypeNeeded
) opInfo
->needsType
, exact_type
, type_char
);
1605 stmt
->error("invalid operand size");
1608 } else if (op
== Op_Branch
) {
1609 if (operands
[0].dataSize
== Far_Ptr
) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
1610 insnTemplate
->writebyte('l');
1611 } else if (op
== Op_fxch
) {
1612 // gas won't accept the two-operand form
1613 if (operands
[1].cls
== Opr_Reg
&& operands
[1].reg
== Reg_ST
) {
1616 stmt
->error("invalid operands");
1624 int mlen
= strlen(mnemonic
);
1625 if (mnemonic
[mlen
-1] == 'd')
1626 insnTemplate
->write(mnemonic
, mlen
-1);
1628 insnTemplate
->writestring((char*) mnemonic
);
1629 insnTemplate
->writebyte('w');
1641 int mlen
= strlen(mnemonic
);
1642 if (mnemonic
[mlen
-1] == 'd') {
1643 insnTemplate
->write(mnemonic
, mlen
-1);
1644 insnTemplate
->writebyte('l');
1646 insnTemplate
->writestring((char*) mnemonic
);
1654 int mlen
= strlen(mnemonic
);
1655 PtrType op1_size
= operands
[1].dataSize
;
1656 if (op1_size
== Default_Ptr
)
1657 op1_size
= operands
[1].dataSizeHint
;
1658 // Need type char for source arg
1668 stmt
->error("invalid operand size/type");
1671 assert(type_char
!= 0);
1672 insnTemplate
->write(mnemonic
, mlen
-1);
1673 insnTemplate
->writebyte(tc_1
);
1674 insnTemplate
->writebyte(type_char
);
1678 insnTemplate
->writestring((char*) mnemonic
);
1680 insnTemplate
->writebyte(type_char
);
1684 switch (opInfo
->implicitClobbers
& Clb_DXAX_Mask
) {
1687 stmt
->regs
|= (1<<Reg_EAX
);
1690 stmt
->regs
|= (1<<Reg_EAX
);
1691 if (type_char
!= 'b')
1692 stmt
->regs
|= (1<<Reg_EDX
);
1699 if (opInfo
->implicitClobbers
& Clb_DI
)
1700 stmt
->regs
|= (1 << Reg_EDI
);
1701 if (opInfo
->implicitClobbers
& Clb_SI
)
1702 stmt
->regs
|= (1 << Reg_ESI
);
1703 if (opInfo
->implicitClobbers
& Clb_CX
)
1704 stmt
->regs
|= (1 << Reg_ECX
);
1705 if (opInfo
->implicitClobbers
& Clb_SP
)
1706 stmt
->regs
|= (1 << Reg_ESP
);
1707 if (opInfo
->implicitClobbers
& Clb_ST
)
1709 /* Can't figure out how to tell GCC that an
1710 asm statement leaves an arg pushed on the stack.
1711 Maybe if the statment had and input or output
1712 operand it would work... In any case, clobbering
1713 all FP prevents incorrect code generation. */
1714 stmt
->regs
|= (1 << Reg_ST
);
1715 stmt
->regs
|= (1 << Reg_ST1
);
1716 stmt
->regs
|= (1 << Reg_ST2
);
1717 stmt
->regs
|= (1 << Reg_ST3
);
1718 stmt
->regs
|= (1 << Reg_ST4
);
1719 stmt
->regs
|= (1 << Reg_ST5
);
1720 stmt
->regs
|= (1 << Reg_ST6
);
1721 stmt
->regs
|= (1 << Reg_ST7
);
1723 if (opInfo
->implicitClobbers
& Clb_Flags
)
1724 asmcode
->moreRegs
|= (1 << (Reg_EFLAGS
- 32));
1726 stmt
->regs
|= (1 << Reg_EAX
)|
1727 (1 << Reg_ECX
)|(1 << Reg_EDX
);
1729 insnTemplate
->writebyte('\t');
1730 for (int i__
= 0; i__
< nOperands
; i__
++) {
1733 insnTemplate
->writestring((char*) ", ");
1739 // gas won't accept the two-operand form; skip to the source operand
1747 i
= nOperands
- 1 - i__
; // operand = & operands[ nOperands - 1 - i ];
1750 operand
= & operands
[ i
];
1752 switch (operand
->cls
) {
1754 // for implementing offset:
1755 // $var + $7 // fails
1759 // DMD doesn't seem to allow this
1761 if (opInfo->takesLabel()) tho... (near ptr <Number> would be abs?)
1762 fmt = "%a"; // GAS won't accept "jmp $42"; must be "jmp 42" (rel) or "jmp *42" (abs)
1764 if (opTakesLabel()/*opInfo->takesLabel()*/) {
1765 // "relative addressing not allowed in branch instructions" ..
1766 stmt
->error("integer constant not allowed in branch instructions");
1770 if (operand
->symbolDisplacement
.dim
&&
1771 isLocalSize( (Expression
*) operand
->symbolDisplacement
.data
[0] )) {
1772 // handle __LOCAL_SIZE, which in this constant, is an immediate
1773 // should do this in slotexp..
1774 addOperand("%", Arg_LocalSize
,
1775 (Expression
*) operand
->symbolDisplacement
.data
[0], asmcode
);
1776 if (operand
->constDisplacement
)
1777 insnTemplate
->writebyte('+');
1782 if (operand
->symbolDisplacement
.dim
) {
1784 addOperand("%", Arg_Pointer
,
1785 (Expression
*) operand
->symbolDisplacement
.data
[0],
1788 if (operand
->constDisplacement
)
1789 insnTemplate
->writebyte('+');
1791 // skip the addOperand(fmt, Arg_Integer...) below
1794 addOperand(fmt
, Arg_Integer
, newIntExp(operand
->constDisplacement
), asmcode
);
1797 if (opInfo
->operands
[i
] & Opr_Dest
) {
1798 Reg clbr_reg
= (Reg
) regInfo
[operand
->reg
].baseReg
;
1799 if (clbr_reg
!= Reg_Invalid
) {
1801 stmt
->regs
|= (1 << clbr_reg
);
1803 asmcode
->moreRegs
|= (1 << (clbr_reg
- 32));
1806 if (opTakesLabel()/*opInfo->takesLabel()*/)
1807 insnTemplate
->writebyte('*');
1808 writeReg(operand
->reg
);
1810 insnTemplate->writestring("%%");
1811 insnTemplate->writestring(regInfo[operand->reg].name);
1815 // better: use output operands for simple variable references
1816 if ( (opInfo
->operands
[i
] & Opr_Update
) == Opr_Update
) {
1818 } else if (opInfo
->operands
[i
] & Opr_Dest
) {
1824 use_star
= opTakesLabel();//opInfo->takesLabel();
1825 if (operand
->segmentPrefix
!= Reg_Invalid
) {
1826 writeReg(operand
->segmentPrefix
);
1827 insnTemplate
->writebyte(':');
1829 if (operand
->symbolDisplacement
.dim
) {
1830 Expression
* e
= (Expression
*) operand
->symbolDisplacement
.data
[0];
1831 Declaration
* decl
= 0;
1833 /* We are generating a memory reference, but the
1834 operand could be a floating point constant. If this
1835 is the case, it will be turned into a const static
1836 VAR_DECL later in AsmStatement::toIR. */
1838 if (e
->op
== TOKvar
)
1839 decl
= ((VarExp
*) e
)->var
;
1841 /* The GCC will error (or just warn) on references to
1842 nonlocal vars, but it cannot catch closure vars. */
1844 /* TODO: Could allow this for the frame-relative
1845 case if it's a closure var. We do not know if
1846 it is a closure var at this point, however.
1847 Just accept it for now and return false from
1848 getFrameRelativeOffset if it turns out not to be.
1850 if (decl
&& !(decl
->isDataseg() || decl
->isCodeseg()) &&
1851 decl
->toParent2() != sc
->func
)
1852 stmt
->error("cannot access nonlocal variable %s", decl
->toChars());
1854 if (operand
->baseReg
!= Reg_Invalid
&&
1855 decl
&& ! decl
->isDataseg()) {
1857 // Use the offset from frame pointer
1859 /* GCC doesn't give the front end access to stack offsets
1860 when optimization is turned on (3.x) or at all (4.x).
1862 Try to convert var[EBP] (or var[ESP] for naked funcs) to
1863 a memory expression that does not require us to know
1867 if (operand
->indexReg
== Reg_Invalid
&&
1868 decl
->isVarDeclaration() &&
1869 ((operand
->baseReg
== Reg_EBP
&& ! sc
->func
->naked
) ||
1870 (operand
->baseReg
== Reg_ESP
&& sc
->func
->naked
)) ) {
1872 e
= new AddrExp(0, e
);
1873 e
->type
= decl
->type
->pointerTo();
1875 /* DMD uses the same frame offsets for naked functions. */
1876 if (sc
->func
->naked
)
1877 operand
->constDisplacement
+= 4;
1879 if (operand
->constDisplacement
) {
1880 e
= new AddExp(0, e
,
1881 new IntegerExp(0, operand
->constDisplacement
,
1883 e
->type
= decl
->type
->pointerTo();
1885 e
= new PtrExp(0, e
);
1886 e
->type
= decl
->type
;
1888 operand
->constDisplacement
= 0;
1889 operand
->baseReg
= Reg_Invalid
;
1891 addOperand(fmt
, Arg_Memory
, e
, asmcode
, mode
);
1894 addOperand("%a", Arg_FrameRelative
, e
, asmcode
);
1896 if (opInfo
->operands
[i
] & Opr_Dest
)
1897 asmcode
->clobbersMemory
= 1;
1899 // Plain memory reference to variable
1901 /* If in a reg, DMD moves to memory.. even with -O, so we'll do the same
1902 by always using the "m" contraint.
1904 In order to get the correct output for function and label symbols,
1905 the %an format must be used with the "p" constraint.
1908 unsigned lbl_num
= ++d_priv_asm_label_serial
;
1910 asmcode
->dollarLabel
= lbl_num
; // could make the dollar label part of the same asm..
1911 } else if (e
->op
== TOKdsymbol
) {
1912 LabelDsymbol
* lbl
= (LabelDsymbol
*) ((DsymbolExp
*) e
)->s
;
1913 if (! lbl
->asmLabelNum
)
1914 lbl
->asmLabelNum
= ++d_priv_asm_label_serial
;
1917 addLabel(lbl
->asmLabelNum
);
1918 } else if ((decl
&& decl
->isCodeseg())) { // if function or label
1920 addOperand("%a", Arg_Pointer
, e
, asmcode
);
1923 insnTemplate
->writebyte('*');
1926 addOperand(fmt
, Arg_Memory
, e
, asmcode
, mode
);
1931 insnTemplate
->writebyte('*');
1932 if (operand
->constDisplacement
) {
1933 if (operand
->symbolDisplacement
.dim
)
1934 insnTemplate
->writebyte('+');
1935 addOperand("%a", Arg_Integer
, newIntExp(operand
->constDisplacement
), asmcode
);
1936 if (opInfo
->operands
[i
] & Opr_Dest
)
1937 asmcode
->clobbersMemory
= 1;
1939 if (operand
->baseReg
!= Reg_Invalid
|| operand
->indexReg
!= Reg_Invalid
) {
1940 insnTemplate
->writebyte('(');
1941 if (operand
->baseReg
!= Reg_Invalid
)
1942 writeReg(operand
->baseReg
);
1943 if (operand
->indexReg
!= Reg_Invalid
) {
1944 insnTemplate
->writebyte(',');
1945 writeReg(operand
->indexReg
);
1946 if (operand
->scale
) {
1947 insnTemplate
->printf(",%d", operand
->scale
);
1950 insnTemplate
->writebyte(')');
1951 if (opInfo
->operands
[i
] & Opr_Dest
)
1952 asmcode
->clobbersMemory
= 1;
1960 asmcode
->insnTemplateLen
= insnTemplate
->offset
;
1961 asmcode
->insnTemplate
= (char*) insnTemplate
->extractData();
1965 bool isIntExp(Expression
* exp
) {
1966 if (exp
->op
== TOKint64
)
1968 if (exp
->op
== TOKvar
) {
1969 Declaration
* v
= ((VarExp
*) exp
)->var
;
1970 if (v
->isConst() && v
->type
->isintegral())
1975 bool isRegExp(Expression
* exp
) { return exp
->op
== TOKmod
; } // ewww.%%
1976 bool isLocalSize(Expression
* exp
) {
1977 // cleanup: make a static var
1978 return exp
->op
== TOKidentifier
&& ((IdentifierExp
*) exp
)->ident
== Id::__LOCAL_SIZE
;
1980 bool isDollar(Expression
* exp
) {
1981 return exp
->op
== TOKidentifier
&& ((IdentifierExp
*) exp
)->ident
== Id::__dollar
;
1984 Expression
* newRegExp(int regno
) {
1985 IntegerExp
* e
= new IntegerExp(regno
);
1990 Expression
* newIntExp(int v
/* %% type */) {
1991 // Only handles 32-bit numbers as this is IA-32.
1992 return new IntegerExp(stmt
->loc
, v
, Type::tint32
);
1995 void slotExp(Expression
* exp
) {
1997 if offset, make a note
1999 if integer, add to immediate
2001 if not in bracket, set reg (else error)
2003 if not base, set base
2004 if not index, set index
2010 bool is_offset
= false;
2011 if (exp
->op
== TOKaddress
) {
2012 exp
= ((AddrExp
*) exp
)->e1
;
2016 if (isIntExp(exp
)) {
2018 invalidExpression();
2019 operand
->constDisplacement
+= exp
->toInteger();
2020 if (! operand
->inBracket
)
2021 operand
->hasNumber
= 1;
2022 } else if (isRegExp(exp
)) {
2024 invalidExpression();
2025 if (! operand
->inBracket
) {
2026 if (operand
->reg
== Reg_Invalid
)
2027 operand
->reg
= (Reg
) exp
->toInteger();
2029 stmt
->error("too many registers in operand (use brackets)");
2031 if (operand
->baseReg
== Reg_Invalid
)
2032 operand
->baseReg
= (Reg
) exp
->toInteger();
2033 else if (operand
->indexReg
== Reg_Invalid
) {
2034 operand
->indexReg
= (Reg
) exp
->toInteger();
2037 stmt
->error("too many registers memory operand");
2040 } else if (exp
->op
== TOKvar
) {
2041 VarDeclaration
* v
= ((VarExp
*) exp
)->var
->isVarDeclaration();
2043 if (v
&& v
->storage_class
& STCfield
) {
2044 operand
->constDisplacement
+= v
->offset
;
2045 if (! operand
->inBracket
)
2046 operand
->hasNumber
= 1;
2048 if (v
&& v
->type
->isscalar())
2050 // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64
2051 TY ty
= v
->type
->toBasetype()->ty
;
2052 operand
->dataSizeHint
= ty
== Tfloat80
|| ty
== Timaginary80
?
2053 Extended_Ptr
: (PtrType
) v
->type
->size(0);
2056 if (! operand
->symbolDisplacement
.dim
) {
2057 if (is_offset
&& ! operand
->inBracket
)
2058 operand
->isOffset
= 1;
2059 operand
->symbolDisplacement
.push( exp
);
2061 stmt
->error("too many symbols in operand");
2064 } else if (exp
->op
== TOKidentifier
|| exp
->op
== TOKdsymbol
) {
2065 // %% localsize could be treated as a simple constant..
2066 // change to addSymbolDisp(e)
2067 if (! operand
->symbolDisplacement
.dim
) {
2068 operand
->symbolDisplacement
.push( exp
);
2070 stmt
->error("too many symbols in operand");
2072 } else if (exp
->op
== TOKfloat64
) {
2073 if (exp
->type
&& exp
->type
->isscalar())
2075 // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64
2076 TY ty
= exp
->type
->toBasetype()->ty
;
2077 operand
->dataSizeHint
= ty
== Tfloat80
|| ty
== Timaginary80
?
2078 Extended_Ptr
: (PtrType
) exp
->type
->size(0);
2080 // Will be converted to a VAR_DECL in AsmStatement::toIR
2081 operand
->symbolDisplacement
.push( exp
);
2082 } else if (exp
== Handled
) {
2085 stmt
->error("invalid operand");
2089 void invalidExpression() {
2090 // %% report operand number
2091 stmt
->error("invalid expression");
2094 Expression
* intOp(TOK op
, Expression
* e1
, Expression
* e2
) {
2096 if (isIntExp(e1
) && (! e2
|| isIntExp(e2
))) {
2100 e
= new AddExp(stmt
->loc
, e1
, e2
);
2106 e
= new MinExp(stmt
->loc
, e1
, e2
);
2108 e
= new NegExp(stmt
->loc
, e1
);
2111 e
= new MulExp(stmt
->loc
, e1
, e2
);
2114 e
= new DivExp(stmt
->loc
, e1
, e2
);
2117 e
= new ModExp(stmt
->loc
, e1
, e2
);
2120 e
= new ShlExp(stmt
->loc
, e1
, e2
);
2123 e
= new ShrExp(stmt
->loc
, e1
, e2
);
2126 e
= new UshrExp(stmt
->loc
, e1
, e2
);
2129 e
= new NotExp(stmt
->loc
, e1
);
2132 e
= new ComExp(stmt
->loc
, e1
);
2137 e
= e
->semantic(sc
);
2138 return e
->optimize(WANTvalue
| WANTinterpret
);
2140 stmt
->error("expected integer operand(s) for '%s'", Token::tochars
[op
]);
2141 return newIntExp(0);
2145 void parseOperand() {
2146 Expression
* exp
= parseAsmExp();
2149 operand
->dataSize
= (PtrType
) regInfo
[exp
->toInteger()].size
;
2152 Expression
* parseAsmExp() {
2153 return parseShiftExp();
2156 Expression
* parseShiftExp() {
2157 Expression
* e1
= parseAddExp();
2161 TOK tv
= token
->value
;
2168 e1
= intOp(tv
, e1
, e2
);
2178 Expression
* parseAddExp() {
2179 Expression
* e1
= parseMultExp();
2183 TOK tv
= token
->value
;
2187 e2
= parseMultExp();
2188 if (isIntExp(e1
) && isIntExp(e2
))
2189 e1
= intOp(tv
, e1
, e2
);
2197 // Note: no support for symbol address difference
2199 e2
= parseMultExp();
2200 if (isIntExp(e1
) && isIntExp(e2
))
2201 e1
= intOp(tv
, e1
, e2
);
2204 e2
= intOp(TOKmin
, e2
, NULL
); // verifies e2 is an int
2217 bool tryScale(Expression
* e1
, Expression
* e2
) {
2219 if (isIntExp(e1
) && isRegExp(e2
)) {
2224 } else if (isRegExp(e1
) && isIntExp(e2
)) {
2226 if (! operand
->inBracket
) {
2227 invalidExpression(); // maybe should allow, e.g. DS:EBX+EAX*4
2230 if (operand
->scale
|| operand
->indexReg
!= Reg_Invalid
) {
2231 invalidExpression();
2235 operand
->indexReg
= (Reg
) e1
->toInteger();
2236 operand
->scale
= e2
->toInteger();
2237 switch (operand
->scale
) {
2245 stmt
->error("invalid index register scale '%d'", operand
->scale
);
2254 Expression
* parseMultExp() {
2255 Expression
* e1
= parseBrExp();
2259 TOK tv
= token
->value
;
2263 e2
= parseMultExp();
2264 if (isIntExp(e1
) && isIntExp(e2
))
2265 e1
= intOp(tv
, e1
, e2
);
2266 else if (tryScale(e1
,e2
))
2269 invalidExpression();
2274 e2
= parseMultExp();
2275 e1
= intOp(tv
, e1
, e2
);
2285 Expression
* parseBrExp() {
2286 // %% check (why is bracket lower precends..)
2287 // 3+4[eax] -> 3 + (4 [EAX]) ..
2289 // only one bracked allowed, so this doesn't quite handle
2290 // the spec'd syntax
2293 if (token
->value
== TOKlbracket
)
2298 // DMD allows multiple bracket expressions.
2299 while (token
->value
== TOKlbracket
) {
2302 operand
->inBracket
= operand
->hasBracket
= 1;
2303 slotExp(parseAsmExp());
2304 operand
->inBracket
= 0;
2306 if (token
->value
== TOKrbracket
)
2309 stmt
->error("missing ']'");
2315 PtrType
isPtrType(Token
* tok
) {
2316 switch (tok
->value
) {
2317 case TOKint8
: return Byte_Ptr
;
2318 case TOKint16
: return Short_Ptr
;
2319 case TOKint32
: return Int_Ptr
;
2320 // 'long ptr' isn't accepted?
2321 case TOKfloat32
: return Float_Ptr
;
2322 case TOKfloat64
: return Double_Ptr
;
2323 case TOKfloat80
: return Extended_Ptr
;
2325 for (int i
= 0; i
< N_PtrNames
; i
++)
2326 if (tok
->ident
== ptrTypeIdentTable
[i
])
2327 return ptrTypeValueTable
[i
];
2335 Expression
* parseUnaExp() {
2336 Expression
* e
= NULL
;
2339 // First, check for type prefix.
2340 if (token
->value
!= TOKeof
&&
2341 peekToken()->value
== TOKidentifier
&&
2342 peekToken()->ident
== Id::ptr
) {
2344 ptr_type
= isPtrType(token
);
2345 if (ptr_type
!= Default_Ptr
) {
2346 if (operand
->dataSize
== Default_Ptr
)
2347 operand
->dataSize
= ptr_type
;
2349 stmt
->error("multiple specifications of operand size");
2351 stmt
->error("unknown operand size '%s'", token
->toChars());
2354 return parseAsmExp();
2357 TOK tv
= token
->value
;
2360 if (token
->ident
== ident_seg
) {
2362 stmt
->error("'seg' not supported");
2364 } else if (token
->ident
== Id::offset
||
2365 token
->ident
== Id::offsetof
) {
2366 if (token
->ident
== Id::offset
&& ! global
.params
.useDeprecated
)
2367 stmt
->error("offset deprecated, use offsetof");
2370 e
= new AddrExp(stmt
->loc
, e
);
2382 return intOp(tv
, e
, NULL
);
2387 return parsePrimaryExp();
2390 Expression
* parsePrimaryExp() {
2392 Identifier
* ident
= NULL
;
2394 switch (token
->value
) {
2400 // %% for tok64 really should use 64bit type
2401 e
= new IntegerExp(stmt
->loc
, token
->uns64value
, Type::tint32
);
2407 // %% need different types?
2408 e
= new RealExp(stmt
->loc
, token
->float80value
, Type::tfloat80
);
2413 ident
= token
->ident
;
2416 if (ident
== Id::__LOCAL_SIZE
) {
2417 return new IdentifierExp(stmt
->loc
, ident
);
2418 } else if (ident
== Id::__dollar
) {
2420 return new IdentifierExp(stmt
->loc
, ident
);
2422 e
= new IdentifierExp(stmt
->loc
, ident
);
2425 // If this is more than one component ref, it gets complicated: *(&Field + n)
2426 // maybe just do one step at a time..
2427 // simple case is Type.f -> VarDecl(field)
2428 // actually, DMD only supports on level...
2429 // X.y+Y.z[EBX] is supported, tho..
2430 // %% doesn't handle properties (check%%)
2431 while (token
->value
== TOKdot
) {
2433 if (token
->value
== TOKidentifier
) {
2434 e
= new DotIdExp(stmt
->loc
, e
, token
->ident
);
2437 stmt
->error("expected identifier");
2442 // check for reg first then dotexp is an error?
2443 if (e
->op
== TOKidentifier
) {
2444 for (int i
= 0; i
< N_Regs
; i
++) {
2445 if (ident
== regInfo
[i
].ident
) {
2446 if ( (Reg
) i
== Reg_ST
&& token
->value
== TOKlparen
) {
2448 switch (token
->value
) {
2449 case TOKint32v
: case TOKuns32v
:
2450 case TOKint64v
: case TOKuns64v
:
2451 if (token
->uns64value
< 8)
2452 e
= newRegExp( (Reg
) (Reg_ST
+ token
->uns64value
) );
2454 stmt
->error("invalid floating point register index");
2458 if (token
->value
== TOKrparen
)
2461 stmt
->error("expected ')'");
2466 invalidExpression();
2468 } else if (token
->value
== TOKcolon
) {
2470 if (operand
->segmentPrefix
!= Reg_Invalid
)
2471 stmt
->error("too many segment prefixes");
2472 else if (i
>= Reg_CS
&& i
<= Reg_GS
)
2473 operand
->segmentPrefix
= (Reg
) i
;
2475 stmt
->error("'%s' is not a segment register", ident
->string
);
2476 return parseAsmExp();
2478 return newRegExp( (Reg
) i
);
2484 if (opTakesLabel()/*opInfo->takesLabel()*/ && e
->op
== TOKidentifier
) {
2485 // DMD uses labels secondarily to other symbols, so check
2486 // if IdentifierExp::semantic won't find anything.
2489 if ( ! sc
->search(stmt
->loc
, ident
, & scopesym
) )
2490 return new DsymbolExp(stmt
->loc
,
2491 sc
->func
->searchLabel( ident
));
2494 e
= e
->semantic(sc
);
2496 /* Special case for floating point literals: Try to
2497 resolve to a memory reference. If not possible,
2498 leave it as a literal and generate an anonymous
2499 var in AsmStatement::toIR.
2501 if (e
->op
== TOKfloat64
) {
2502 Dsymbol
* sym
= sc
->search(stmt
->loc
, ident
, NULL
);
2504 VarDeclaration
*v
= sym
->isVarDeclaration();
2505 if ( v
&& v
->isDataseg() ) {
2506 Expression
*ve
= new VarExp(stmt
->loc
, v
);
2517 ident
= Id::__dollar
;
2521 invalidExpression();
2528 // .align bits vs. bytes...
2529 // apparently a.out platforms use bits instead of bytes...
2531 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2'
2532 // GAS is padding with NOPs last time I checked.
2533 Expression
* e
= parseAsmExp()->optimize(WANTvalue
| WANTinterpret
);
2534 integer_t align
= e
->toInteger();
2537 // %% is this printf portable?
2538 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
2539 insnTemplate
->printf(".balign\t%u", (unsigned) align
);
2541 insnTemplate
->printf(".align\t%u", (unsigned) align
);
2544 stmt
->error("alignment must be a power of 2");
2551 // .align for GAS is in bits, others probably use bytes..
2552 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
2553 insnTemplate
->writestring((char *) ".align\t2");
2555 insnTemplate
->writestring((char *) ".align\t2");
2561 // %% can we assume sc->func != 0?
2562 sc
->func
->naked
= 1;
2566 static const char * directives
[] = { ".byte", ".short", ".long", ".long",
2571 insnTemplate
->writestring((char*) directives
[op
- Op_db
]);
2572 insnTemplate
->writebyte('\t');
2575 // DMD is pretty strict here, not even constant expressions are allowed..
2581 if (token
->value
== TOKint32v
|| token
->value
== TOKuns32v
||
2582 token
->value
== TOKint64v
|| token
->value
== TOKuns64v
) {
2583 // As per usual with GNU, assume at least 32-bit host
2585 insnTemplate
->printf("%u", (d_uns32
) token
->uns64value
);
2587 // Output two .longS. GAS has .quad, but would have to rely on 'L' format ..
2588 // just need to use HOST_WIDE_INT_PRINT_DEC
2589 insnTemplate
->printf("%u,%u",
2590 (d_uns32
) token
->uns64value
, (d_uns32
) (token
->uns64value
>> 32));
2593 stmt
->error("expected integer constant");
2603 #ifndef TARGET_80387
2604 #define XFmode TFmode
2606 mode
= XFmode
; // not TFmode
2609 if (token
->value
== TOKfloat32v
|| token
->value
== TOKfloat64v
||
2610 token
->value
== TOKfloat80v
) {
2612 real_to_target(words
, & token
->float80value
.rv(), mode
);
2613 // don't use directives..., just use .long like GCC
2614 insnTemplate
->printf(".long\t%u", words
[0]);
2616 insnTemplate
->printf(",%u", words
[1]);
2617 // DMD outputs 10 bytes, so we need to switch to .short here
2619 insnTemplate
->printf("\n\t.short\t%u", words
[2]);
2621 stmt
->error("expected float constant");
2629 if (token
->value
== TOKcomma
) {
2630 insnTemplate
->writebyte(',');
2632 } else if (token
->value
== TOKeof
) {
2635 stmt
->error("expected comma");
2644 // struct rtx was modified for c++; this macro from rtl.h needs to
2645 // be modified accordingly.
2647 #define XEXP(RTX, N) (RTL_CHECK2 (RTX, N, 'e', 'u').rt_rtx)
2650 bool getFrameRelativeValue(tree decl
, HOST_WIDE_INT
* result
)
2652 /* Using this instead of DECL_RTL for struct args seems like a
2653 good way to get hit by a truck because it may not agree with
2654 non-asm access, but asm code wouldn't know what GCC does anyway. */
2655 rtx r
= DECL_INCOMING_RTL(decl
);
2658 // Local variables don't have DECL_INCOMING_RTL
2662 if (r
!= NULL_RTX
&& GET_CODE(r
) == MEM
/* && r->frame_related */ ) {
2664 if (GET_CODE(r
) == PLUS
) {
2667 if (e1
== virtual_incoming_args_rtx
&& GET_CODE(e2
) == CONST_INT
) {
2668 *result
= INTVAL(e2
) + 8; // %% 8 is 32-bit specific...
2670 } else if (e1
== virtual_stack_vars_rtx
&& GET_CODE(e2
) == CONST_INT
) {
2671 *result
= INTVAL(e2
); // %% 8 is 32-bit specific...
2674 } else if (r
== virtual_incoming_args_rtx
) {
2676 return true; // %% same as above
2678 // shouldn't have virtual_stack_vars_rtx by itself