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