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