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 }