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