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