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