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