Mercurial > projects > ddmd
annotate dmd/AssignExp.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 | 60bb0fe4563e |
children | b0d41ff5e0df |
rev | line source |
---|---|
72 | 1 module dmd.AssignExp; |
2 | |
114 | 3 import dmd.common; |
72 | 4 import dmd.Expression; |
5 import dmd.Identifier; | |
6 import dmd.backend.elem; | |
7 import dmd.InterState; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
8 import dmd.Parameter; |
72 | 9 import dmd.IndexExp; |
10 import dmd.CallExp; | |
11 import dmd.CastExp; | |
12 import dmd.TypeSArray; | |
13 import dmd.StructLiteralExp; | |
14 import dmd.ArrayLengthExp; | |
15 import dmd.TypeStruct; | |
16 import dmd.StructDeclaration; | |
17 import dmd.VarExp; | |
18 import dmd.TY; | |
19 import dmd.SliceExp; | |
20 import dmd.CommaExp; | |
21 import dmd.ArrayExp; | |
22 import dmd.AggregateDeclaration; | |
23 import dmd.CondExp; | |
24 import dmd.DotVarExp; | |
25 import dmd.WANT; | |
26 import dmd.Id; | |
27 import dmd.TypeClass; | |
28 import dmd.OutBuffer; | |
29 import dmd.Loc; | |
30 import dmd.TypeNext; | |
31 import dmd.TupleExp; | |
32 import dmd.VarDeclaration; | |
33 import dmd.Scope; | |
34 import dmd.IRState; | |
35 import dmd.ArrayTypes; | |
36 import dmd.BinExp; | |
37 import dmd.TOK; | |
38 import dmd.Global; | |
39 import dmd.Declaration; | |
40 import dmd.TypeFunction; | |
41 import dmd.Type; | |
42 import dmd.RET; | |
43 import dmd.STC; | |
44 import dmd.DotIdExp; | |
45 | |
46 import dmd.backend.Util; | |
47 import dmd.backend.Symbol; | |
48 import dmd.backend.OPER; | |
49 import dmd.backend.TYM; | |
50 import dmd.backend.RTLSYM; | |
51 import dmd.codegen.Util; | |
52 import dmd.expression.Util; | |
53 | |
0 | 54 class AssignExp : BinExp |
55 { | |
56 int ismemset = 0; | |
57 | |
58 this(Loc loc, Expression e1, Expression e2) | |
59 { | |
178 | 60 register(); |
61 | |
0 | 62 super(loc, TOK.TOKassign, AssignExp.sizeof, e1, e2); |
63 } | |
64 | |
72 | 65 override Expression semantic(Scope sc) |
0 | 66 { |
72 | 67 Expression e1old = e1; |
68 | |
69 version (LOGSEMANTIC) { | |
70 printf("AssignExp.semantic('%s')\n", toChars()); | |
71 } | |
72 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op)); | |
73 //printf("e2.op = %d, '%s'\n", e2.op, Token.toChars(e2.op)); | |
74 | |
75 if (type) | |
76 return this; | |
77 | |
78 if (e2.op == TOK.TOKcomma) | |
79 { | |
80 /* Rewrite to get rid of the comma from rvalue | |
81 */ | |
82 AssignExp ea = new AssignExp(loc, e1, (cast(CommaExp)e2).e2); | |
83 ea.op = op; | |
84 Expression e = new CommaExp(loc, (cast(CommaExp)e2).e1, ea); | |
85 return e.semantic(sc); | |
86 } | |
87 | |
88 /* Look for operator overloading of a[i]=value. | |
89 * Do it before semantic() otherwise the a[i] will have been | |
90 * converted to a.opIndex() already. | |
91 */ | |
92 if (e1.op == TOK.TOKarray) | |
93 { | |
94 ArrayExp ae = cast(ArrayExp)e1; | |
95 AggregateDeclaration ad; | |
96 Identifier id = Id.index; | |
97 | |
98 ae.e1 = ae.e1.semantic(sc); | |
99 Type t1 = ae.e1.type.toBasetype(); | |
100 if (t1.ty == TY.Tstruct) | |
101 { | |
102 ad = (cast(TypeStruct)t1).sym; | |
103 goto L1; | |
104 } | |
105 else if (t1.ty == TY.Tclass) | |
106 { | |
107 ad = (cast(TypeClass)t1).sym; | |
108 L1: | |
109 // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) | |
110 if (search_function(ad, Id.indexass)) | |
111 { | |
112 Expression e = new DotIdExp(loc, ae.e1, Id.indexass); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
113 auto a = ae.arguments.copy(); |
72 | 114 |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
115 a.insert(0, e2); |
72 | 116 e = new CallExp(loc, e, a); |
117 e = e.semantic(sc); | |
118 return e; | |
119 } | |
120 else | |
121 { | |
122 // Rewrite (a[i] = value) to (a.opIndex(i, value)) | |
123 if (search_function(ad, id)) | |
124 { | |
125 Expression e = new DotIdExp(loc, ae.e1, id); | |
126 | |
127 if (1 || !global.params.useDeprecated) | |
128 error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); | |
129 | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
130 e = new CallExp(loc, e, ae.arguments[0], e2); |
72 | 131 e = e.semantic(sc); |
132 return e; | |
133 } | |
134 } | |
135 } | |
136 } | |
137 /* Look for operator overloading of a[i..j]=value. | |
138 * Do it before semantic() otherwise the a[i..j] will have been | |
139 * converted to a.opSlice() already. | |
140 */ | |
141 if (e1.op == TOK.TOKslice) | |
142 { | |
143 Type t1; | |
144 SliceExp ae = cast(SliceExp)e1; | |
145 AggregateDeclaration ad; | |
146 Identifier id = Id.index; | |
147 | |
148 ae.e1 = ae.e1.semantic(sc); | |
149 ae.e1 = resolveProperties(sc, ae.e1); | |
150 t1 = ae.e1.type.toBasetype(); | |
151 if (t1.ty == TY.Tstruct) | |
152 { | |
153 ad = (cast(TypeStruct)t1).sym; | |
154 goto L2; | |
155 } | |
156 else if (t1.ty == TY.Tclass) | |
157 { | |
158 ad = (cast(TypeClass)t1).sym; | |
159 L2: | |
160 // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) | |
161 if (search_function(ad, Id.sliceass)) | |
162 { | |
163 Expression e = new DotIdExp(loc, ae.e1, Id.sliceass); | |
164 Expressions a = new Expressions(); | |
165 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
166 a.push(e2); |
72 | 167 if (ae.lwr) |
168 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
169 a.push(ae.lwr); |
72 | 170 assert(ae.upr); |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
171 a.push(ae.upr); |
72 | 172 } |
173 else | |
174 assert(!ae.upr); | |
175 | |
176 e = new CallExp(loc, e, a); | |
177 e = e.semantic(sc); | |
178 return e; | |
179 } | |
180 } | |
181 } | |
182 | |
183 BinExp.semantic(sc); | |
184 | |
185 if (e1.op == TOK.TOKdottd) | |
186 { | |
187 // Rewrite a.b=e2, when b is a template, as a.b(e2) | |
188 Expression e = new CallExp(loc, e1, e2); | |
189 e = e.semantic(sc); | |
190 return e; | |
191 } | |
192 | |
193 e2 = resolveProperties(sc, e2); | |
194 assert(e1.type); | |
195 | |
196 /* Rewrite tuple assignment as a tuple of assignments. | |
197 */ | |
198 if (e1.op == TOK.TOKtuple && e2.op == TOK.TOKtuple) | |
199 { | |
200 TupleExp tup1 = cast(TupleExp)e1; | |
201 TupleExp tup2 = cast(TupleExp)e2; | |
202 size_t dim = tup1.exps.dim; | |
203 if (dim != tup2.exps.dim) | |
204 { | |
205 error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim); | |
206 } | |
207 else | |
208 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
209 auto exps = new Expressions; |
72 | 210 exps.setDim(dim); |
211 | |
212 for (int i = 0; i < dim; i++) | |
213 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
214 auto ex1 = tup1.exps[i]; |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
215 auto ex2 = tup2.exps[i]; |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
216 exps[i] = new AssignExp(loc, ex1, ex2); |
72 | 217 } |
218 Expression e = new TupleExp(loc, exps); | |
219 e = e.semantic(sc); | |
220 return e; | |
221 } | |
222 } | |
223 | |
224 // Determine if this is an initialization of a reference | |
225 int refinit = 0; | |
226 if (op == TOK.TOKconstruct && e1.op == TOK.TOKvar) | |
227 { | |
228 VarExp ve = cast(VarExp)e1; | |
229 VarDeclaration v = ve.var.isVarDeclaration(); | |
230 if (v.storage_class & (STC.STCout | STC.STCref)) | |
231 refinit = 1; | |
232 } | |
233 | |
234 Type t1 = e1.type.toBasetype(); | |
235 | |
236 if (t1.ty == TY.Tfunction) | |
237 { | |
238 // Rewrite f=value to f(value) | |
239 Expression e = new CallExp(loc, e1, e2); | |
240 e = e.semantic(sc); | |
241 return e; | |
242 } | |
243 | |
244 /* If it is an assignment from a 'foreign' type, | |
245 * check for operator overloading. | |
246 */ | |
247 if (t1.ty == TY.Tstruct) | |
248 { | |
249 StructDeclaration sd = (cast(TypeStruct)t1).sym; | |
250 if (op == TOK.TOKassign) | |
251 { | |
252 Expression e = op_overload(sc); | |
253 if (e) | |
254 return e; | |
255 } | |
256 else if (op == TOK.TOKconstruct && !refinit) | |
257 { | |
258 Type t2 = e2.type.toBasetype(); | |
259 if (t2.ty == TY.Tstruct && sd == (cast(TypeStruct)t2).sym && sd.cpctor) | |
260 { | |
261 /* We have a copy constructor for this | |
262 */ | |
263 if (e2.op == TOK.TOKquestion) | |
264 { /* Write as: | |
265 * a ? e1 = b : e1 = c; | |
266 */ | |
267 CondExp ec = cast(CondExp)e2; | |
268 AssignExp ea1 = new AssignExp(ec.e1.loc, e1, ec.e1); | |
269 ea1.op = op; | |
270 AssignExp ea2 = new AssignExp(ec.e1.loc, e1, ec.e2); | |
271 ea2.op = op; | |
272 Expression e = new CondExp(loc, ec.econd, ea1, ea2); | |
273 return e.semantic(sc); | |
274 } | |
275 else if (e2.op == TOK.TOKvar || e2.op == TOK.TOKdotvar || e2.op == TOK.TOKstar || e2.op == TOK.TOKindex) | |
276 { /* Write as: | |
277 * e1.cpctor(e2); | |
278 */ | |
279 Expression e = new DotVarExp(loc, e1, sd.cpctor, 0); | |
280 e = new CallExp(loc, e, e2); | |
281 return e.semantic(sc); | |
282 } | |
283 } | |
284 } | |
285 } | |
286 else if (t1.ty == TY.Tclass) | |
287 { | |
288 // Disallow assignment operator overloads for same type | |
289 if (!e2.type.implicitConvTo(e1.type)) | |
290 { | |
291 Expression e = op_overload(sc); | |
292 if (e) | |
293 return e; | |
294 } | |
295 } | |
296 | |
297 if (t1.ty == TY.Tsarray && !refinit) | |
298 { | |
299 // Convert e1 to e1[] | |
300 Expression e = new SliceExp(e1.loc, e1, null, null); | |
301 e1 = e.semantic(sc); | |
302 t1 = e1.type.toBasetype(); | |
303 } | |
304 | |
305 e2.rvalue(); | |
306 | |
307 if (e1.op == TOK.TOKarraylength) | |
308 { | |
309 // e1 is not an lvalue, but we let code generator handle it | |
310 ArrayLengthExp ale = cast(ArrayLengthExp)e1; | |
311 ale.e1 = ale.e1.modifiableLvalue(sc, e1); | |
312 } | |
313 else if (e1.op == TOK.TOKslice) | |
314 { | |
315 Type tn = e1.type.nextOf(); | |
316 if (tn && !tn.isMutable() && op != TOK.TOKconstruct) | |
317 error("slice %s is not mutable", e1.toChars()); | |
318 } | |
319 else | |
320 { | |
321 // Try to do a decent error message with the expression | |
322 // before it got constant folded | |
323 if (e1.op != TOK.TOKvar) | |
324 e1 = e1.optimize(WANT.WANTvalue); | |
325 | |
326 if (op != TOK.TOKconstruct) | |
327 e1 = e1.modifiableLvalue(sc, e1old); | |
328 } | |
329 | |
330 Type t2 = e2.type; | |
331 if (e1.op == TOK.TOKslice && t1.nextOf() && e2.implicitConvTo(t1.nextOf())) | |
332 { | |
333 // memset | |
334 ismemset = 1; // make it easy for back end to tell what this is | |
335 e2 = e2.implicitCastTo(sc, t1.nextOf()); | |
336 } | |
337 else if (t1.ty == TY.Tsarray) | |
338 { | |
339 /* Should have already converted e1 => e1[] | |
340 */ | |
341 assert(op == TOK.TOKconstruct); | |
342 //error("cannot assign to static array %s", e1.toChars()); | |
343 } | |
344 else if (e1.op == TOK.TOKslice) | |
345 { | |
346 e2 = e2.implicitCastTo(sc, e1.type.constOf()); | |
347 } | |
348 else | |
349 { | |
350 e2 = e2.implicitCastTo(sc, e1.type); | |
351 } | |
352 | |
353 /* Look for array operations | |
354 */ | |
355 if (e1.op == TOK.TOKslice && !ismemset && | |
356 (e2.op == TOK.TOKadd || e2.op == TOK.TOKmin || | |
357 e2.op == TOK.TOKmul || e2.op == TOK.TOKdiv || | |
358 e2.op == TOK.TOKmod || e2.op == TOK.TOKxor || | |
359 e2.op == TOK.TOKand || e2.op == TOK.TOKor || | |
360 e2.op == TOK.TOKtilde || e2.op == TOK.TOKneg)) | |
361 { | |
362 type = e1.type; | |
363 return arrayOp(sc); | |
364 } | |
365 | |
366 type = e1.type; | |
367 assert(type); | |
0 | 368 return this; |
369 } | |
370 | |
72 | 371 override Expression checkToBoolean() |
0 | 372 { |
373 assert(false); | |
374 } | |
375 | |
72 | 376 override Expression interpret(InterState istate) |
0 | 377 { |
63 | 378 return interpretAssignCommon(istate, null); |
0 | 379 } |
380 | |
72 | 381 override Identifier opId() |
0 | 382 { |
383 return Id.assign; | |
384 } | |
385 | |
72 | 386 override void buildArrayIdent(OutBuffer buf, Expressions arguments) |
0 | 387 { |
72 | 388 /* Evaluate assign expressions right to left |
389 */ | |
390 e2.buildArrayIdent(buf, arguments); | |
391 e1.buildArrayIdent(buf, arguments); | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
392 buf.writestring("Assign"); |
0 | 393 } |
394 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
395 override Expression buildArrayLoop(Parameters fparams) |
0 | 396 { |
72 | 397 /* Evaluate assign expressions right to left |
398 */ | |
399 Expression ex2 = e2.buildArrayLoop(fparams); | |
400 version (DMDV2) { | |
401 /* Need the cast because: | |
402 * b = c + p[i]; | |
403 * where b is a byte fails because (c + p[i]) is an int | |
404 * which cannot be implicitly cast to byte. | |
405 */ | |
406 ex2 = new CastExp(Loc(0), ex2, e1.type.nextOf()); | |
407 } | |
408 Expression ex1 = e1.buildArrayLoop(fparams); | |
126
1765f3ef917d
ClassDeclarations, Arguments -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
409 auto param = fparams[0]; |
72 | 410 param.storageClass = STCundefined; |
411 Expression e = new AssignExp(Loc(0), ex1, ex2); | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
412 return e; |
0 | 413 } |
414 | |
72 | 415 override elem* toElem(IRState* irs) |
0 | 416 { |
72 | 417 Type t1b; |
418 | |
419 //printf("AssignExp.toElem('%s')\n", toChars()); | |
420 t1b = e1.type.toBasetype(); | |
421 | |
422 // Look for array.length = n | |
423 if (e1.op == TOK.TOKarraylength) | |
424 { | |
425 // Generate: | |
426 // _d_arraysetlength(e2, sizeelem, &ale.e1); | |
427 | |
428 ArrayLengthExp ale = cast(ArrayLengthExp)e1; | |
429 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
430 auto p1 = e2.toElem(irs); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
431 auto p3 = ale.e1.toElem(irs); |
72 | 432 p3 = addressElem(p3, null); |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
433 Type t1 = ale.e1.type.toBasetype(); |
72 | 434 |
435 // call _d_arraysetlengthT(ti, e2, &ale.e1); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
436 auto p2 = t1.getTypeInfo(null).toElem(irs); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
437 auto ep = el_params(p3, p1, p2, null); // c function |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
438 int r = t1.nextOf().isZeroInit(Loc(0)) ? RTLSYM.RTLSYM_ARRAYSETLENGTHT : RTLSYM.RTLSYM_ARRAYSETLENGTHIT; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
439 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
440 auto e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[r]), ep); |
72 | 441 el_setLoc(e, loc); |
442 return e; | |
443 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
444 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
445 elem *e; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
446 IndexExp ae; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
447 |
72 | 448 // Look for array[]=n |
449 if (e1.op == TOK.TOKslice) | |
450 { | |
451 Type t1 = t1b; | |
452 Type t2 = e2.type.toBasetype(); | |
453 | |
454 // which we do if the 'next' types match | |
455 if (ismemset) | |
456 { | |
457 // Do a memset for array[]=v | |
458 //printf("Lpair %s\n", toChars()); | |
459 SliceExp are = cast(SliceExp)e1; | |
460 elem* elwr; | |
461 elem* eupr; | |
462 elem* n1; | |
463 elem* evalue; | |
464 elem* enbytes; | |
465 elem* elength; | |
466 elem* einit; | |
467 long value; | |
468 Type ta = are.e1.type.toBasetype(); | |
469 Type tb = ta.nextOf().toBasetype(); | |
470 int sz = cast(uint)tb.size(); | |
471 tym_t tym = type.totym(); | |
472 | |
473 n1 = are.e1.toElem(irs); | |
474 elwr = are.lwr ? are.lwr.toElem(irs) : null; | |
475 eupr = are.upr ? are.upr.toElem(irs) : null; | |
476 | |
477 elem* n1x = n1; | |
478 | |
479 // Look for array[]=n | |
480 if (ta.ty == TY.Tsarray) | |
481 { | |
482 TypeSArray ts = cast(TypeSArray)ta; | |
483 n1 = array_toPtr(ta, n1); | |
484 enbytes = ts.dim.toElem(irs); | |
485 n1x = n1; | |
486 n1 = el_same(&n1x); | |
487 einit = resolveLengthVar(are.lengthVar, &n1, ta); | |
488 } | |
489 else if (ta.ty == TY.Tarray) | |
490 { | |
491 n1 = el_same(&n1x); | |
492 einit = resolveLengthVar(are.lengthVar, &n1, ta); | |
493 enbytes = el_copytree(n1); | |
494 n1 = array_toPtr(ta, n1); | |
495 enbytes = el_una(OPER.OP64_32, TYM.TYint, enbytes); | |
496 } | |
497 else if (ta.ty == TY.Tpointer) | |
498 { | |
499 n1 = el_same(&n1x); | |
500 enbytes = el_long(TYM.TYint, -1); // largest possible index | |
501 einit = null; | |
502 } | |
503 | |
504 // Enforce order of evaluation of n1[elwr..eupr] as n1,elwr,eupr | |
505 elem* elwrx = elwr; | |
506 if (elwr) elwr = el_same(&elwrx); | |
507 elem* euprx = eupr; | |
508 if (eupr) eupr = el_same(&euprx); | |
509 | |
510 static if (false) { | |
511 printf("sz = %d\n", sz); | |
512 printf("n1x\n"); | |
513 elem_print(n1x); | |
514 printf("einit\n"); | |
515 elem_print(einit); | |
516 printf("elwrx\n"); | |
517 elem_print(elwrx); | |
518 printf("euprx\n"); | |
519 elem_print(euprx); | |
520 printf("n1\n"); | |
521 elem_print(n1); | |
522 printf("elwr\n"); | |
523 elem_print(elwr); | |
524 printf("eupr\n"); | |
525 elem_print(eupr); | |
526 printf("enbytes\n"); | |
527 elem_print(enbytes); | |
528 } | |
529 einit = el_combine(n1x, einit); | |
530 einit = el_combine(einit, elwrx); | |
531 einit = el_combine(einit, euprx); | |
532 | |
533 evalue = this.e2.toElem(irs); | |
534 | |
535 static if (false) { | |
536 printf("n1\n"); | |
537 elem_print(n1); | |
538 printf("enbytes\n"); | |
539 elem_print(enbytes); | |
540 } | |
541 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
542 if (irs.arrayBoundsCheck() && eupr && ta.ty != TY.Tpointer) |
72 | 543 { |
544 elem *c1; | |
545 elem *c2; | |
546 elem *ea; | |
547 elem *eb; | |
548 elem *enbytesx; | |
549 | |
550 assert(elwr); | |
551 enbytesx = enbytes; | |
552 enbytes = el_same(&enbytesx); | |
553 c1 = el_bin(OPER.OPle, TYM.TYint, el_copytree(eupr), enbytesx); | |
554 c2 = el_bin(OPER.OPle, TYM.TYint, el_copytree(elwr), el_copytree(eupr)); | |
555 c1 = el_bin(OPER.OPandand, TYM.TYint, c1, c2); | |
556 | |
557 // Construct: (c1 || ModuleArray(line)) | |
558 Symbol *sassert; | |
559 | |
560 sassert = irs.blx.module_.toModuleArray(); | |
561 ea = el_bin(OPER.OPcall,TYM.TYvoid,el_var(sassert), el_long(TYM.TYint, loc.linnum)); | |
562 eb = el_bin(OPER.OPoror,TYM.TYvoid,c1,ea); | |
563 einit = el_combine(einit, eb); | |
564 } | |
565 | |
566 if (elwr) | |
567 { | |
568 elem *elwr2; | |
569 | |
570 el_free(enbytes); | |
571 elwr2 = el_copytree(elwr); | |
572 elwr2 = el_bin(OPER.OPmul, TYM.TYint, elwr2, el_long(TYM.TYint, sz)); | |
573 n1 = el_bin(OPER.OPadd, TYM.TYnptr, n1, elwr2); | |
574 enbytes = el_bin(OPER.OPmin, TYM.TYint, eupr, elwr); | |
575 elength = el_copytree(enbytes); | |
576 } | |
577 else | |
578 elength = el_copytree(enbytes); | |
579 | |
580 e = setArray(n1, enbytes, tb, evalue, irs, op); | |
581 Lpair: | |
582 e = el_pair(TYM.TYullong, elength, e); | |
583 Lret2: | |
584 e = el_combine(einit, e); | |
585 //elem_print(e); | |
586 goto Lret; | |
587 } | |
588 ///static if (false) { | |
589 /// else if (e2.op == TOK.TOKadd || e2.op == TOK.TOKmin) | |
590 /// { | |
591 /// /* It's ea[] = eb[] +- ec[] | |
592 /// */ | |
593 /// BinExp e2a = cast(BinExp)e2; | |
594 /// Type t = e2.type.toBasetype().nextOf().toBasetype(); | |
595 /// if (t.ty != TY.Tfloat32 && t.ty != TY.Tfloat64 && t.ty != TY.Tfloat80) | |
596 /// { | |
597 /// e2.error("array add/min for %s not supported", t.toChars()); | |
598 /// return el_long(TYM.TYint, 0); | |
599 /// } | |
600 /// elem* ea = e1.toElem(irs); | |
601 /// ea = array_toDarray(e1.type, ea); | |
602 /// elem* eb = e2a.e1.toElem(irs); | |
603 /// eb = array_toDarray(e2a.e1.type, eb); | |
604 /// elem* ec = e2a.e2.toElem(irs); | |
605 /// ec = array_toDarray(e2a.e2.type, ec); | |
606 /// | |
607 /// int rtl = RTLSYM.RTLSYM_ARRAYASSADDFLOAT; | |
608 /// if (t.ty == Tfloat64) | |
609 /// rtl = RTLSYM.RTLSYM_ARRAYASSADDDOUBLE; | |
610 /// else if (t.ty == Tfloat80) | |
611 /// rtl = RTLSYM.RTLSYM_ARRAYASSADDREAL; | |
612 /// if (e2.op == TOK.TOKmin) | |
613 /// { | |
614 /// rtl = RTLSYM.RTLSYM_ARRAYASSMINFLOAT; | |
615 /// if (t.ty == Tfloat64) | |
616 /// rtl = RTLSYM.RTLSYM_ARRAYASSMINDOUBLE; | |
617 /// else if (t.ty == Tfloat80) | |
618 /// rtl = RTLSYM.RTLSYM_ARRAYASSMINREAL; | |
619 /// } | |
620 /// | |
621 /// /* Set parameters so the order of evaluation is eb, ec, ea | |
622 /// */ | |
623 /// elem* ep = el_params(eb, ec, ea, null); | |
624 /// e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[rtl]), ep); | |
625 /// goto Lret; | |
626 /// } | |
627 ///} | |
628 else | |
629 { | |
630 /* It's array1[]=array2[] | |
631 * which is a memcpy | |
632 */ | |
633 elem* ep; | |
634 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
635 auto eto = e1.toElem(irs); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
636 auto efrom = e2.toElem(irs); |
72 | 637 |
638 uint size = cast(uint)t1.nextOf().size(); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
639 auto esize = el_long(TYM.TYint, size); |
72 | 640 |
641 /* Determine if we need to do postblit | |
642 */ | |
643 int postblit = 0; | |
644 if (needsPostblit(t1)) | |
645 postblit = 1; | |
646 | |
647 assert(e2.type.ty != TY.Tpointer); | |
648 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
649 if (!postblit && !irs.arrayBoundsCheck()) |
72 | 650 { |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
651 auto ex = el_same(&eto); |
72 | 652 |
653 // Determine if elen is a constant | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
654 elem *elen; |
72 | 655 if (eto.Eoper == OPER.OPpair && eto.E1.Eoper == OPER.OPconst) |
656 { | |
657 elen = el_copytree(eto.E1); | |
658 } | |
659 else | |
660 { | |
661 // It's not a constant, so pull it from the dynamic array | |
662 elen = el_una(OPER.OP64_32, TYM.TYint, el_copytree(ex)); | |
663 } | |
664 | |
665 esize = el_bin(OPER.OPmul, TYM.TYint, elen, esize); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
666 auto epto = array_toPtr(e1.type, ex); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
667 auto epfr = array_toPtr(e2.type, efrom); |
72 | 668 static if (true) { |
669 // memcpy() is faster, so if we can't beat 'em, join 'em | |
670 e = el_params(esize, epfr, epto, null); | |
671 e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[RTLSYM.RTLSYM_MEMCPY]), e); | |
672 } else { | |
673 e = el_bin(OPER.OPmemcpy, TYM.TYnptr, epto, el_param(epfr, esize)); | |
674 } | |
675 e = el_pair(eto.Ety, el_copytree(elen), e); | |
676 e = el_combine(eto, e); | |
677 } | |
678 ///version (DMDV2) { | |
679 else if (postblit && op != TOK.TOKblit) | |
680 { | |
681 /* Generate: | |
682 * _d_arrayassign(ti, efrom, eto) | |
683 * or: | |
684 * _d_arrayctor(ti, efrom, eto) | |
685 */ | |
686 el_free(esize); | |
687 Expression ti = t1.nextOf().toBasetype().getTypeInfo(null); | |
688 ep = el_params(eto, efrom, ti.toElem(irs), null); | |
689 int rtl = (op == TOK.TOKconstruct) ? RTLSYM.RTLSYM_ARRAYCTOR : RTLSYM.RTLSYM_ARRAYASSIGN; | |
690 e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[rtl]), ep); | |
691 } | |
692 ///} | |
693 else | |
694 { | |
695 // Generate: | |
696 // _d_arraycopy(eto, efrom, esize) | |
697 | |
698 ep = el_params(eto, efrom, esize, null); | |
699 e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[RTLSYM.RTLSYM_ARRAYCOPY]), ep); | |
700 } | |
701 el_setLoc(e, loc); | |
702 return e; | |
703 } | |
704 } | |
705 | |
706 if (e1.op == TOK.TOKindex) | |
707 { | |
708 elem* eb; | |
709 elem* ei; | |
710 elem* ev; | |
711 TY ty; | |
712 Type ta; | |
713 | |
714 ae = cast(IndexExp)e1; | |
715 ta = ae.e1.type.toBasetype(); | |
716 ty = ta.ty; | |
717 } | |
718 | |
719 version (DMDV2) { | |
720 /* Look for reference initializations | |
721 */ | |
722 if (op == TOK.TOKconstruct && e1.op == TOK.TOKvar) | |
723 { | |
724 VarExp ve = cast(VarExp)e1; | |
725 Declaration s = ve.var; | |
726 if (s.storage_class & STC.STCref) | |
727 { | |
728 static if (false) { | |
729 Expression ae = e2.addressOf(null); | |
730 e = ae.toElem(irs); | |
731 } else { | |
732 e = e2.toElem(irs); | |
733 e = addressElem(e, e2.type); | |
734 } | |
735 elem* es = el_var(s.toSymbol()); | |
736 es.Ety = TYM.TYnptr; | |
737 e = el_bin(OPER.OPeq, TYM.TYnptr, es, e); | |
738 // BUG: type is struct, and e2 is TOKint64 | |
739 goto Lret; | |
740 } | |
741 } | |
742 } | |
743 | |
744 static if (true) { | |
745 /* This will work if we can distinguish an assignment from | |
746 * an initialization of the lvalue. It'll work if the latter. | |
747 * If the former, because of aliasing of the return value with | |
748 * function arguments, it'll fail. | |
749 */ | |
750 if (op == TOK.TOKconstruct && e2.op == TOK.TOKcall) | |
751 { | |
752 CallExp ce = cast(CallExp)e2; | |
753 | |
754 Type t = ce.e1.type.toBasetype(); | |
755 if (t.ty == TY.Tfunction) { | |
756 TypeFunction tf = cast(TypeFunction)t; | |
757 if (tf.retStyle() == RET.RETstack) | |
758 { | |
759 elem* ehidden = e1.toElem(irs); | |
760 ehidden = el_una(OPER.OPaddr, TYM.TYnptr, ehidden); | |
761 assert(!irs.ehidden); | |
762 irs.ehidden = ehidden; | |
763 e = e2.toElem(irs); | |
764 goto Lret; | |
765 } | |
766 } | |
767 } | |
768 } | |
769 //printf("test2 %d\n", op); | |
770 //if (op == TOK.TOKconstruct) printf("construct\n"); | |
771 if (t1b.ty == TY.Tstruct) | |
772 { | |
773 elem* eleft = e1.toElem(irs); | |
774 | |
775 if (e2.op == TOK.TOKint64) | |
776 { | |
777 /* Implement: | |
778 * (struct = 0) | |
779 * with: | |
780 * memset(&struct, 0, struct.sizeof) | |
781 */ | |
782 elem* ey = null; | |
783 int sz = cast(int)e1.type.size(); | |
784 StructDeclaration sd = (cast(TypeStruct)t1b).sym; | |
785 if (sd.isnested && op == TOK.TOKconstruct) | |
786 { | |
787 ey = el_una(OPER.OPaddr, TYM.TYnptr, eleft); | |
788 eleft = el_same(&ey); | |
789 ey = setEthis(loc, irs, ey, sd); | |
790 sz = sd.vthis.offset; | |
791 } | |
792 | |
793 elem *el = eleft; | |
794 elem *enbytes = el_long(TYM.TYint, sz); | |
795 elem *evalue = el_long(TYM.TYint, 0); | |
796 | |
797 if (!(sd.isnested && op == TOK.TOKconstruct)) | |
798 el = el_una(OPER.OPaddr, TYM.TYnptr, el); | |
799 | |
800 e = el_param(enbytes, evalue); | |
801 e = el_bin(OPER.OPmemset, TYM.TYnptr,el,e); | |
802 e = el_combine(ey, e); | |
803 el_setLoc(e, loc); | |
804 //e = el_una(OPER.OPind, TYM.TYstruct, e); | |
805 } | |
806 else | |
807 { | |
808 //printf("toElemBin() '%s'\n", toChars()); | |
809 | |
810 tym_t tym = type.totym(); | |
811 | |
812 elem* e1 = eleft; | |
813 elem* ex = e1; | |
814 if (e1.Eoper == OPER.OPind) | |
815 ex = e1.E1; | |
816 | |
817 if (this.e2.op == TOK.TOKstructliteral && ex.Eoper == OPER.OPvar && ex.EV.sp.Voffset == 0) | |
818 { | |
819 StructLiteralExp se = cast(StructLiteralExp)this.e2; | |
820 | |
821 Symbol* symSave = se.sym; | |
822 size_t soffsetSave = se.soffset; | |
823 int fillHolesSave = se.fillHoles; | |
824 | |
825 se.sym = ex.EV.sp.Vsym; | |
826 se.soffset = 0; | |
827 se.fillHoles = (op == TOK.TOKconstruct || op == TOK.TOKblit) ? 1 : 0; | |
828 | |
829 el_free(e1); | |
830 e = this.e2.toElem(irs); | |
831 | |
832 se.sym = symSave; | |
833 se.soffset = soffsetSave; | |
834 se.fillHoles = fillHolesSave; | |
835 } | |
836 else | |
837 { | |
838 elem* e2 = this.e2.toElem(irs); | |
839 e = el_bin(OPER.OPstreq,tym,e1,e2); | |
840 e.Enumbytes = cast(uint)this.e1.type.size(); | |
841 } | |
842 goto Lret; | |
843 } | |
844 } | |
845 else | |
846 e = toElemBin(irs,OPER.OPeq); | |
847 | |
848 return e; | |
849 | |
850 Lret: | |
851 el_setLoc(e,loc); | |
0 | 852 return e; |
853 } | |
854 } | |
855 |