Mercurial > projects > ddmd
comparison dmd/AsmStatement.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 3f834bed4f13 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:10317f0c89a5 |
---|---|
1 module dmd.AsmStatement; | |
2 | |
3 import dmd.Loc; | |
4 import dmd.Statement; | |
5 import dmd.Token; | |
6 import dmd.Scope; | |
7 import dmd.OutBuffer; | |
8 import dmd.HdrGenState; | |
9 import dmd.IRState; | |
10 import dmd.BE; | |
11 import dmd.LabelDsymbol; | |
12 import dmd.Dsymbol; | |
13 import dmd.Id; | |
14 import dmd.TOK; | |
15 import dmd.Global; | |
16 import dmd.FuncDeclaration; | |
17 import dmd.Declaration; | |
18 import dmd.LabelStatement; | |
19 import dmd.Util; | |
20 | |
21 import dmd.backend.code; | |
22 import dmd.backend.iasm; | |
23 import dmd.backend.block; | |
24 import dmd.backend.Blockx; | |
25 import dmd.backend.Util; | |
26 import dmd.codegen.Util; | |
27 import dmd.backend.BC; | |
28 import dmd.backend.FL; | |
29 import dmd.backend.SFL; | |
30 import dmd.backend.SC; | |
31 import dmd.backend.mTY; | |
32 import dmd.backend.Symbol; | |
33 import dmd.backend.LIST; | |
34 | |
35 import core.stdc.string : memset; | |
36 import core.stdc.stdlib : exit, EXIT_FAILURE; | |
37 | |
38 class AsmStatement : Statement | |
39 { | |
40 Token* tokens; | |
41 code* asmcode; | |
42 uint asmalign; // alignment of this statement | |
43 bool refparam; // true if function parameter is referenced | |
44 bool naked; // true if function is to be naked | |
45 uint regs; // mask of registers modified | |
46 | |
47 this(Loc loc, Token* tokens) | |
48 { | |
49 super(loc); | |
50 this.tokens = tokens; | |
51 } | |
52 | |
53 Statement syntaxCopy() | |
54 { | |
55 assert(false); | |
56 } | |
57 | |
58 Statement semantic(Scope sc) | |
59 { | |
60 //printf("AsmStatement.semantic()\n"); | |
61 | |
62 if (global.params.safe && !sc.module_.safe) | |
63 { | |
64 error("inline assembler not allowed in safe mode"); | |
65 } | |
66 | |
67 OP* o; | |
68 OPND* o1 = null; | |
69 OPND* o2 = null; | |
70 OPND* o3 = null; | |
71 | |
72 PTRNTAB ptb; | |
73 uint usNumops; | |
74 ubyte uchPrefix = 0; | |
75 ubyte bAsmseen; | |
76 char* pszLabel = null; | |
77 code* c; | |
78 FuncDeclaration fd = sc.parent.isFuncDeclaration(); | |
79 | |
80 assert(fd); | |
81 fd.inlineAsm = 1; | |
82 | |
83 if (!tokens) | |
84 return null; | |
85 | |
86 memset(&asmstate, 0, asmstate.sizeof); | |
87 | |
88 asmstate.statement = this; | |
89 asmstate.sc = sc; | |
90 | |
91 static if (false) { | |
92 // don't use bReturnax anymore, and will fail anyway if we use return type inference | |
93 // Scalar return values will always be in AX. So if it is a scalar | |
94 // then asm block sets return value if it modifies AX, if it is non-scalar | |
95 // then always assume that the ASM block sets up an appropriate return | |
96 // value. | |
97 | |
98 asmstate.bReturnax = 1; | |
99 if (sc.func.type.nextOf().isscalar()) | |
100 asmstate.bReturnax = 0; | |
101 } | |
102 | |
103 // Assume assembler code takes care of setting the return value | |
104 sc.func.hasReturnExp |= 8; | |
105 | |
106 if (!asmstate.bInit) | |
107 { | |
108 asmstate.bInit = true; | |
109 init_optab(); | |
110 asmstate.psDollar = new LabelDsymbol(Id.__dollar); | |
111 //asmstate.psLocalsize = new VarDeclaration(0, Type.tint32, Id.__LOCAL_SIZE, null); | |
112 asmstate.psLocalsize = new Dsymbol(Id.__LOCAL_SIZE); | |
113 cod3_set386(); | |
114 } | |
115 | |
116 asmstate.loc = loc; | |
117 | |
118 asmtok = tokens; | |
119 asm_token_trans(asmtok); | |
120 if (setjmp(asmstate.env)) | |
121 { | |
122 asmtok = null; // skip rest of line | |
123 tok_value = TOK.TOKeof; | |
124 exit(EXIT_FAILURE); | |
125 goto AFTER_EMIT; | |
126 } | |
127 | |
128 switch (cast(int)tok_value) | |
129 { | |
130 case ASMTK.ASMTKnaked: | |
131 naked = true; | |
132 sc.func.naked = true; | |
133 asm_token(); | |
134 break; | |
135 | |
136 case ASMTK.ASMTKeven: | |
137 asm_token(); | |
138 asmalign = 2; | |
139 break; | |
140 | |
141 case TOK.TOKalign: | |
142 { | |
143 asm_token(); | |
144 uint align_ = asm_getnum(); | |
145 if (ispow2(align_) == -1) | |
146 asmerr(ASMERRMSGS.EM_align, align_); // power of 2 expected | |
147 else | |
148 asmalign = align_; | |
149 break; | |
150 } | |
151 | |
152 // The following three convert the keywords 'int', 'in', 'out' | |
153 // to identifiers, since they are x86 instructions. | |
154 case TOK.TOKint32: | |
155 o = asm_op_lookup(Id.__int.toChars()); | |
156 goto Lopcode; | |
157 | |
158 case TOK.TOKin: | |
159 o = asm_op_lookup(Id.___in.toChars()); | |
160 goto Lopcode; | |
161 | |
162 case TOK.TOKout: | |
163 o = asm_op_lookup(Id.___out.toChars()); | |
164 goto Lopcode; | |
165 | |
166 case TOK.TOKidentifier: | |
167 o = asm_op_lookup(asmtok.ident.toChars()); | |
168 if (!o) | |
169 goto OPCODE_EXPECTED; | |
170 | |
171 Lopcode: | |
172 asmstate.ucItype = o.usNumops & IT.ITMASK; | |
173 asm_token(); | |
174 if (o.usNumops > 3) | |
175 { | |
176 switch (asmstate.ucItype) | |
177 { | |
178 case IT.ITdata: | |
179 asmcode = asm_db_parse(o); | |
180 goto AFTER_EMIT; | |
181 | |
182 case IT.ITaddr: | |
183 asmcode = asm_da_parse(o); | |
184 goto AFTER_EMIT; | |
185 | |
186 default: | |
187 break; | |
188 } | |
189 } | |
190 // get the first part of an expr | |
191 o1 = asm_cond_exp(); | |
192 if (tok_value == TOK.TOKcomma) | |
193 { | |
194 asm_token(); | |
195 o2 = asm_cond_exp(); | |
196 } | |
197 if (tok_value == TOK.TOKcomma) | |
198 { | |
199 asm_token(); | |
200 o3 = asm_cond_exp(); | |
201 } | |
202 // match opcode and operands in ptrntab to verify legal inst and | |
203 // generate | |
204 | |
205 ptb = asm_classify(o, o1, o2, o3, &usNumops); | |
206 assert(ptb.pptb0); | |
207 | |
208 // | |
209 // The Multiply instruction takes 3 operands, but if only 2 are seen | |
210 // then the third should be the second and the second should | |
211 // be a duplicate of the first. | |
212 // | |
213 | |
214 if (asmstate.ucItype == IT.ITopt && | |
215 (usNumops == 2) && | |
216 (ASM_GET_aopty(o2.usFlags) == ASM_OPERAND_TYPE._imm) && | |
217 ((o.usNumops & IT.ITSIZE) == 3)) | |
218 { | |
219 o3 = o2; | |
220 o2 = opnd_calloc(); | |
221 *o2 = *o1; | |
222 | |
223 // Re-classify the opcode because the first classification | |
224 // assumed 2 operands. | |
225 | |
226 ptb = asm_classify(o, o1, o2, o3, &usNumops); | |
227 } | |
228 else | |
229 { | |
230 static if (false) { | |
231 if (asmstate.ucItype == IT.ITshift && (ptb.pptb2.usOp2 == 0 || | |
232 (ptb.pptb2.usOp2 & _cl))) { | |
233 opnd_free(o2); | |
234 o2 = null; | |
235 usNumops = 1; | |
236 } | |
237 } | |
238 } | |
239 | |
240 asmcode = asm_emit(loc, usNumops, ptb, o, o1, o2, o3); | |
241 break; | |
242 | |
243 default: | |
244 OPCODE_EXPECTED: | |
245 asmerr(ASMERRMSGS.EM_opcode_exp, asmtok.toChars()); // assembler opcode expected | |
246 break; | |
247 } | |
248 | |
249 AFTER_EMIT: | |
250 opnd_free(o1); | |
251 opnd_free(o2); | |
252 opnd_free(o3); | |
253 o1 = o2 = o3 = null; | |
254 | |
255 if (tok_value != TOK.TOKeof) | |
256 asmerr(ASMERRMSGS.EM_eol); // end of line expected | |
257 | |
258 //return asmstate.bReturnax; | |
259 return this; | |
260 } | |
261 | |
262 BE blockExit() | |
263 { | |
264 assert(false); | |
265 } | |
266 | |
267 bool comeFrom() | |
268 { | |
269 assert(false); | |
270 } | |
271 | |
272 void toCBuffer(OutBuffer buf, HdrGenState* hgs) | |
273 { | |
274 assert(false); | |
275 } | |
276 | |
277 AsmStatement isAsmStatement() { return this; } | |
278 | |
279 void toIR(IRState *irs) | |
280 { | |
281 block* bpre; | |
282 block* basm; | |
283 Declaration d; | |
284 Symbol* s; | |
285 Blockx* blx = irs.blx; | |
286 | |
287 // dumpCode(asmcode); | |
288 | |
289 //printf("AsmStatement::toIR(asmcode = %x)\n", asmcode); | |
290 bpre = blx.curblock; | |
291 block_next(blx,BCgoto,null); | |
292 basm = blx.curblock; | |
293 list_append(&bpre.Bsucc, basm); | |
294 basm.Bcode = asmcode; | |
295 basm.Balign = cast(ubyte)asmalign; | |
296 static if (false) { | |
297 if (label) | |
298 { | |
299 block* b = labelToBlock(loc, blx, label); | |
300 printf("AsmStatement::toIR() %p\n", b); | |
301 if (b) | |
302 list_append(&basm.Bsucc, b); | |
303 } | |
304 } | |
305 // Loop through each instruction, fixing Dsymbols into Symbol's | |
306 for (code* c = asmcode; c; c = c.next) | |
307 { | |
308 LabelDsymbol label; | |
309 block* b; | |
310 | |
311 switch (c.IFL1) | |
312 { | |
313 case FLblockoff: | |
314 case FLblock: | |
315 // FLblock and FLblockoff have LabelDsymbol's - convert to blocks | |
316 label = c.IEVlsym1; | |
317 b = labelToBlock(loc, blx, label); | |
318 list_append(&basm.Bsucc, b); | |
319 c.IEV1.Vblock = b; | |
320 break; | |
321 | |
322 case FLdsymbol: | |
323 case FLfunc: | |
324 s = c.IEVdsym1.toSymbol(); | |
325 if (s.Sclass == SCauto && s.Ssymnum == -1) | |
326 symbol_add(s); | |
327 c.IEVsym1() = s; | |
328 c.IFL1 = s.Sfl ? s.Sfl : FLauto; | |
329 break; | |
330 default: | |
331 break; | |
332 } | |
333 | |
334 // Repeat for second operand | |
335 switch (c.IFL2) | |
336 { | |
337 case FLblockoff: | |
338 case FLblock: | |
339 label = c.IEVlsym2; | |
340 b = labelToBlock(loc, blx, label); | |
341 list_append(&basm.Bsucc, b); | |
342 c.IEV2.Vblock = b; | |
343 break; | |
344 | |
345 case FLdsymbol: | |
346 case FLfunc: | |
347 d = c.IEVdsym2; | |
348 s = d.toSymbol(); | |
349 if (s.Sclass == SCauto && s.Ssymnum == -1) | |
350 symbol_add(s); | |
351 c.IEVsym2() = s; | |
352 c.IFL2 = s.Sfl ? s.Sfl : FLauto; | |
353 if (d.isDataseg()) | |
354 s.Sflags |= SFLlivexit; | |
355 break; | |
356 default: | |
357 break; | |
358 } | |
359 //c.print(); | |
360 } | |
361 | |
362 basm.bIasmrefparam = refparam; // are parameters reference? | |
363 basm.usIasmregs = cast(ushort)regs; // registers modified | |
364 | |
365 block_next(blx,BCasm, null); | |
366 list_prepend(&basm.Bsucc, blx.curblock); | |
367 | |
368 if (naked) | |
369 { | |
370 blx.funcsym.Stype.Tty |= mTYnaked; | |
371 } | |
372 } | |
373 } |