"enum A:B {}" -> "enum A extends B:"
[delight/core.git] / d-glue.cc
blobf054b14eea684ae71dfebb2e5685b1f790a1a49b
1 /* GDC -- D front-end for GCC
2 Copyright (C) 2004 David Friedman
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "d-gcc-includes.h"
21 // from DMD
22 #include "total.h"
23 #include "init.h"
24 #include "symbol.h"
25 #include "d-lang.h"
26 #include "d-codegen.h"
28 // see d-convert.cc
29 tree
30 convert (tree type, tree expr)
32 Type * target_type = g.irs->getDType(type);
33 Type * expr_type = g.irs->getDType(TREE_TYPE(expr));
34 if (target_type && expr_type)
35 return g.irs->convertTo(expr, expr_type, target_type);
36 else
37 return d_convert_basic(type, expr);
40 elem *
41 CondExp::toElem(IRState * irs)
43 tree cn = irs->convertForCondition( econd );
44 tree t1 = e1->toElem( irs );
45 tree t2 = e2->toElem( irs );
46 return build(COND_EXPR, type->toCtype(), cn, t1, t2);
49 static void
50 signed_compare_check(tree * e1, tree * e2)
52 tree t1 = TREE_TYPE( *e1 );
53 tree t2 = TREE_TYPE( *e2 );
54 if (INTEGRAL_TYPE_P( t1 ) &&
55 INTEGRAL_TYPE_P( t2 )) {
56 int u1 = TREE_UNSIGNED( t1 );
57 int u2 = TREE_UNSIGNED( t2 );
59 if (u1 ^ u2) {
60 if (gen.warnSignCompare) {
61 d_warning (0, "unsigned comparison with signed operand");
63 if (! u1)
64 * e1 = convert( d_unsigned_type( t1 ), * e1 );
65 if (! u2)
66 * e2 = convert( d_unsigned_type( t2 ), * e2 );
71 static tree
72 make_bool_binop(TOK op, tree e1, tree e2, IRState * irs)
74 bool is_compare = false; // %% should this be true for unordered comparisons?
75 tree_code out_code;
77 switch (op) {
78 case TOKidentity: // fall through
79 case TOKequal:
80 is_compare = true;
81 out_code = EQ_EXPR;
82 break;
83 case TOKnotidentity: // fall through
84 case TOKnotequal:
85 is_compare = true;
86 out_code = NE_EXPR;
87 break;
88 case TOKandand:
89 out_code = TRUTH_ANDIF_EXPR;
90 break;
91 case TOKoror:
92 out_code = TRUTH_ORIF_EXPR;
93 break;
94 default:
96 // ordering for complex isn't defined, all that is guaranteed is the 'unordered part'
97 case TOKule:
98 case TOKul:
99 case TOKuge:
100 case TOKug:
102 if ( COMPLEX_FLOAT_TYPE_P( TREE_TYPE( e1 )) ) {
103 // GCC doesn't handle these.
104 e1 = irs->maybeMakeTemp(e1);
105 e2 = irs->maybeMakeTemp(e2);
106 switch (op) {
107 case TOKleg:
108 return irs->boolOp(TRUTH_ANDIF_EXPR,
109 make_bool_binop(TOKleg, irs->realPart(e1), irs->realPart(e2), irs),
110 make_bool_binop(TOKleg, irs->imagPart(e1), irs->imagPart(e2), irs));
111 case TOKunord:
112 return irs->boolOp(TRUTH_ORIF_EXPR,
113 make_bool_binop(TOKunord, irs->realPart(e1), irs->realPart(e2), irs),
114 make_bool_binop(TOKunord, irs->imagPart(e1), irs->imagPart(e2), irs));
115 case TOKlg:
116 return irs->boolOp(TRUTH_ANDIF_EXPR,
117 make_bool_binop(TOKleg, e1, e2, irs),
118 make_bool_binop(TOKnotequal, e1, e2, irs));
119 case TOKue:
120 return irs->boolOp(TRUTH_ORIF_EXPR,
121 make_bool_binop(TOKunord, e1, e2, irs),
122 make_bool_binop(TOKequal, e1, e2, irs));
123 default:
125 // From cmath2.d: if imaginary parts are equal,
126 // result is comparison of real parts; otherwise, result false
128 // Does D define an ordering for complex numbers?
130 // make a target-independent _cmplxCmp ?
131 tree it, rt;
132 TOK hard, soft;
133 bool unordered = false;
134 switch (op) {
135 case TOKule:
136 case TOKul:
137 case TOKuge:
138 case TOKug:
139 unordered = true;
140 default:
141 break;
144 switch (op) {
145 case TOKule:
146 case TOKle:
147 hard = TOKlt;
148 soft = TOKle;
149 break;
150 case TOKul:
151 case TOKlt:
152 hard = soft = TOKlt;
153 break;
154 case TOKuge:
155 case TOKge:
156 hard = TOKlt;
157 soft = TOKle;
158 break;
159 case TOKug:
160 case TOKgt:
161 hard = soft = TOKgt;
162 break;
163 default:
164 assert(0);
167 it = make_bool_binop(hard, irs->imagPart(e2), irs->imagPart(e1), irs);
168 if (! unordered)
169 it = irs->boolOp(TRUTH_ANDIF_EXPR,
170 make_bool_binop(TOKleg, irs->realPart(e2), irs->realPart(e1), irs),
171 it);
172 rt = irs->boolOp(TRUTH_ANDIF_EXPR,
173 make_bool_binop(TOKequal, irs->imagPart(e2), irs->imagPart(e1), irs),
174 make_bool_binop(soft, irs->realPart(e2), irs->realPart(e1), irs));
175 it = irs->boolOp(TRUTH_ANDIF_EXPR, it, rt);
176 if (unordered)
177 it = irs->boolOp(TRUTH_ORIF_EXPR,
178 make_bool_binop(TOKunord, e1, e2, irs),
179 it);
180 return it;
184 // else, normal
186 switch (op) {
187 case TOKlt: out_code = LT_EXPR; is_compare = true; break;
188 case TOKgt: out_code = GT_EXPR; is_compare = true; break;
189 case TOKle: out_code = LE_EXPR; is_compare = true; break;
190 case TOKge: out_code = GE_EXPR; is_compare = true; break;
191 case TOKunord: out_code = UNORDERED_EXPR; break;
192 case TOKlg:
194 e1 = irs->maybeMakeTemp(e1);
195 e2 = irs->maybeMakeTemp(e2);
196 return irs->boolOp(TRUTH_ORIF_EXPR,
197 build(LT_EXPR, boolean_type_node, e1, e2),
198 build(GT_EXPR, boolean_type_node, e1, e2));
200 break;
201 default:
202 /* GCC 3.4 (others?) chokes on these unless
203 at least one operand is floating point. */
204 if (FLOAT_TYPE_P( TREE_TYPE( e1 )) &&
205 FLOAT_TYPE_P( TREE_TYPE( e2 ))) {
206 switch (op) {
207 case TOKleg: out_code = ORDERED_EXPR; break;
208 case TOKule: out_code = UNLE_EXPR; break;
209 case TOKul: out_code = UNLT_EXPR; break;
210 case TOKuge: out_code = UNGE_EXPR; break;
211 case TOKug: out_code = UNGT_EXPR; break;
212 case TOKue: out_code = UNEQ_EXPR; break;
213 default:
214 abort();
216 } else {
217 switch (op) {
218 case TOKleg:
219 // %% is this properly optimized away?
220 return irs->voidCompound(irs->compound(e1,e2),
221 convert(boolean_type_node, integer_one_node));
222 break;
223 case TOKule: out_code = LE_EXPR; break;
224 case TOKul: out_code = LT_EXPR; break;
225 case TOKuge: out_code = GE_EXPR; break;
226 case TOKug: out_code = GT_EXPR; break;
227 case TOKue: out_code = EQ_EXPR; break;
228 default:
229 abort();
235 if (is_compare)
236 signed_compare_check(& e1, & e2);
238 tree t = build(out_code, boolean_type_node, // exp->type->toCtype(),
239 e1, e2);
240 #if D_GCC_VER >= 40
241 /* Need to use fold(). Otherwise, complex-var == complex-cst is not
242 gimplified correctly. */
244 if (COMPLEX_FLOAT_TYPE_P( TREE_TYPE( e1 )) ||
245 COMPLEX_FLOAT_TYPE_P( TREE_TYPE( e2 )))
246 t = fold(t);
247 #endif
248 return t;
251 static tree
252 make_bool_binop(BinExp * exp, IRState * irs)
254 tree t1 = exp->e1->toElem(irs);
255 tree t2 = exp->e2->toElem(irs);
256 if (exp->op == TOKandand || exp->op == TOKoror) {
257 t1 = irs->convertForCondition(t1, exp->e1->type);
258 t2 = irs->convertForCondition(t2, exp->e2->type);
260 tree t = make_bool_binop(exp->op, t1, t2, irs);
261 return convert(exp->type->toCtype(), t);
264 elem *
265 IdentityExp::toElem(IRState* irs)
267 TY ty1 = e1->type->toBasetype()->ty;
269 // Assuming types are the same from typeCombine
270 //if (ty1 != e2->type->toBasetype()->ty)
271 //abort();
273 switch (ty1) {
274 case Tsarray:
275 return build(op == TOKidentity ? EQ_EXPR : NE_EXPR,
276 type->toCtype(),
277 irs->addressOf(e1->toElem(irs)),
278 irs->addressOf(e2->toElem(irs)));
279 case Treference:
280 case Tclass:
281 case Tarray:
282 return make_bool_binop(this, irs);
283 default:
284 // For operand types other than class objects, static or dynamic
285 // arrays, identity is defined as being the same as equality
287 // Assumes object == object has been changed to function call
288 // ... impl is really the same as the special cales
289 return make_bool_binop(this, irs);
293 elem *
294 EqualExp::toElem(IRState* irs)
296 Type * base_type_1 = e1->type->toBasetype();
297 TY base_ty_1 = base_type_1->ty;
298 TY base_ty_2 = e2->type->toBasetype()->ty;
300 if ( (base_ty_1 == Tsarray || base_ty_1 == Tarray ||
301 base_ty_2 == Tsarray || base_ty_2 == Tarray) ) {
303 Type * elem_type = base_type_1->nextOf()->toBasetype();
305 // _adCmp compares each element. If bitwise comparison is ok,
306 // use memcmp.
308 if (elem_type->isfloating() || elem_type->isClassHandle() ||
309 elem_type->ty == Tsarray || elem_type->ty == Tarray ||
310 elem_type->ty == Tstruct)
312 tree args[3] = {
313 irs->toDArray(e1),
314 irs->toDArray(e2),
315 irs->typeinfoReference(elem_type) };
316 tree result = irs->libCall(LIBCALL_ADEQ, 3, args);
317 result = convert(type->toCtype(), result);
318 if (op == TOKnotequal)
319 result = build1(TRUTH_NOT_EXPR, type->toCtype(), result);
320 return result;
321 } else if (base_ty_1 == Tsarray && base_ty_2 == Tsarray) {
322 // assuming sizes are equal
323 // shouldn't need to check for Tbit
324 return make_bool_binop(this, irs);
325 } else {
326 tree len_expr[2];
327 tree data_expr[2];
329 gcc_assert(elem_type->ty != Tbit);
331 for (int i = 0; i < 2; i++) {
332 Expression * e = i == 0 ? e1 : e2;
333 TY e_base_ty = i == 0 ? base_ty_1 : base_ty_2;
335 if ( e_base_ty == Tarray ) {
336 tree array_expr = irs->maybeMakeTemp( e->toElem(irs) );
338 data_expr[i] = irs->darrayPtrRef( array_expr );
339 len_expr[i] = irs->darrayLenRef( array_expr ); // may be used twice -- should be okay
340 } else {
341 data_expr[i] = irs->addressOf( e->toElem(irs) );
342 len_expr[i] = ((TypeSArray *) e->type->toBasetype())->dim->toElem(irs);
346 tree t_memcmp = built_in_decls[BUILT_IN_MEMCMP];
347 tree result;
348 tree size;
350 size = build(MULT_EXPR, size_type_node,
351 convert(size_type_node, len_expr[0]), // should be size_type already, though
352 size_int(elem_type->size()));
353 size = fold( size );
355 result = irs->buildCall( TREE_TYPE(TREE_TYPE( t_memcmp )),
356 irs->addressOf( t_memcmp ),
357 tree_cons( NULL_TREE, data_expr[0],
358 tree_cons( NULL_TREE, data_expr[1],
359 tree_cons( NULL_TREE, size, NULL_TREE ))));
361 result = irs->boolOp(op == TOKequal ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR,
362 irs->boolOp(op == TOKequal ? EQ_EXPR : NE_EXPR, len_expr[0], len_expr[1]),
363 irs->boolOp(op == TOKequal ? EQ_EXPR : NE_EXPR, result, integer_zero_node));
365 return convert(type->toCtype(), result);
367 } else {
368 // Taarray case not defined in spec, probably should be a library call
369 return make_bool_binop(this, irs);
373 elem *
374 InExp::toElem(IRState * irs)
376 Type * e2_base_type = e2->type->toBasetype();
377 AddrOfExpr aoe;
378 assert( e2_base_type->ty == Taarray );
380 tree args[3];
381 Type * key_type = ((TypeAArray *) e2_base_type)->index->toBasetype();
382 args[0] = e2->toElem(irs);
383 args[1] = irs->typeinfoReference(key_type);
384 args[2] = aoe.set(irs, irs->convertTo( e1, key_type ) );
385 return d_convert_basic(type->toCtype(),
386 aoe.finish(irs, irs->libCall(LIBCALL_AAINP, 3, args) ));
389 elem *
390 CmpExp::toElem(IRState* irs)
392 Type * base_type_1 = e1->type->toBasetype();
393 TY base_ty_1 = base_type_1->ty;
394 TY base_ty_2 = e2->type->toBasetype()->ty;
396 if ( (base_ty_1 == Tsarray || base_ty_1 == Tarray ||
397 base_ty_2 == Tsarray || base_ty_2 == Tarray) ) {
399 Type * elem_type = base_type_1->nextOf()->toBasetype();
400 tree args[3];
401 unsigned n_args = 2;
402 LibCall lib_call;
404 args[0] = irs->toDArray(e1);
405 args[1] = irs->toDArray(e2);
407 switch (elem_type->ty) {
408 case Tvoid:
409 lib_call = LIBCALL_ADCMPCHAR;
410 break;
411 default:
412 gcc_assert(elem_type->ty != Tbit);
414 // Tuns8, Tchar, Tbool
415 if (elem_type->size() == 1 && elem_type->isscalar() &&
416 elem_type->isunsigned())
417 lib_call = LIBCALL_ADCMPCHAR;
418 else
420 args[2] = irs->typeinfoReference(elem_type);
421 n_args = 3;
422 lib_call = LIBCALL_ADCMP;
424 break;
427 tree result = irs->libCall(lib_call, n_args, args);
428 enum tree_code out_code;
430 // %% For float element types, warn that NaN is not taken into account ?
432 switch (this->op) {
433 case TOKlt: out_code = LT_EXPR; break;
434 case TOKgt: out_code = GT_EXPR; break;
435 case TOKle: out_code = LE_EXPR; break;
436 case TOKge: out_code = GE_EXPR; break;
438 case TOKlg: out_code = NE_EXPR; break;
439 case TOKunord:
440 case TOKleg:
441 // %% Could do a check for side effects and drop the unused condition
442 return build(COMPOUND_EXPR, boolean_type_node,
443 result,
444 d_truthvalue_conversion( this->op == TOKunord ? integer_zero_node : integer_one_node ));
445 case TOKule: out_code = LE_EXPR; break;
446 case TOKul: out_code = LT_EXPR; break;
447 case TOKuge: out_code = GE_EXPR; break;
448 case TOKug: out_code = GT_EXPR; break;
449 case TOKue: out_code = EQ_EXPR; break;
450 break;
451 default:
452 abort();
453 return 0;
456 result = build(out_code, boolean_type_node, result, integer_zero_node);
457 return convert(type->toCtype(), result);
458 } else {
459 return make_bool_binop(this, irs);
463 static tree
464 make_math_op(TOK op, tree e1, Type * e1_type, tree e2, Type * e2_type, Type * exp_type, IRState * irs)
466 // Integral promotions have already been done in the front end
467 tree_code out_code;
469 // %% faster: check if result is complex
470 if (( ( e1_type->isreal() && e2_type->isimaginary() ) ||
471 ( e1_type->isimaginary() && e2_type->isreal() )) &&
472 (op == TOKadd || op == TOKmin )) {
473 // %%TODO: need to check size/modes
474 tree e2_adj;
475 tree e_real, e_imag;
477 if (op == TOKadd) {
478 e2_adj = e2;
479 } else {
480 e2_adj = build1(NEGATE_EXPR, TREE_TYPE(e2), e2);
483 if (e1_type->isreal()) {
484 e_real = e1;
485 e_imag = e2_adj;
486 } else {
487 e_real = e2_adj;
488 e_imag = e1;
491 return build(COMPLEX_EXPR, exp_type->toCtype(), e_real, e_imag);
493 } else {
494 switch (op) {
495 case TOKadd: out_code = PLUS_EXPR; break;
496 case TOKmin: out_code = MINUS_EXPR; break;
497 case TOKmul: out_code = MULT_EXPR; break;
498 case TOKxor: out_code = BIT_XOR_EXPR; break;
499 case TOKor: out_code = BIT_IOR_EXPR; break;
500 case TOKand: out_code = BIT_AND_EXPR; break;
501 case TOKshl: out_code = LSHIFT_EXPR; break;
502 case TOKushr: // drop through
503 case TOKshr: out_code = RSHIFT_EXPR; break;
504 case TOKmod:
505 if (e1_type->isintegral())
506 out_code = TRUNC_MOD_EXPR;
507 else {
508 return irs->floatMod(e1, e2, e1_type);
510 break;
511 case TOKdiv:
512 if (e1_type->isintegral())
513 out_code = TRUNC_DIV_EXPR;
514 else {
515 out_code = RDIV_EXPR;
517 break;
518 default:
519 abort();
523 bool is_unsigned = e1_type->isunsigned() || e2_type->isunsigned()
524 || op == TOKushr;
525 if (exp_type->isintegral() &&
526 ( exp_type->isunsigned() != 0 ) != is_unsigned) {
527 tree e_new_type_1 = is_unsigned ?
528 d_unsigned_type(exp_type->toCtype()) :
529 d_signed_type(exp_type->toCtype());
530 tree t = build(out_code, e_new_type_1, e1, e2);
531 return convert(exp_type->toCtype(), t);
532 } else {
533 /* Front-end does not do this conversion and GCC does not
534 always do it right. */
535 tree_code tc1 = TREE_CODE(TREE_TYPE(e1));
536 tree_code tc2 = TREE_CODE(TREE_TYPE(e2));
537 if (tc1 == COMPLEX_TYPE && tc2 != COMPLEX_TYPE)
538 e2 = irs->convertTo(e2, e2_type, e1_type);
539 else if (tc2 == COMPLEX_TYPE && tc1 != COMPLEX_TYPE)
540 e1 = irs->convertTo(e1, e1_type, e2_type);
542 return build(out_code, exp_type->toCtype(), e1, e2);
546 tree
547 make_math_op(BinExp * exp, IRState * irs)
549 return make_math_op(exp->op,
550 exp->e1->toElem(irs), exp->e1->type,
551 exp->e2->toElem(irs), exp->e2->type,
552 exp->type, irs);
556 elem *
557 AndAndExp::toElem(IRState * irs)
559 if (e2->type->toBasetype()->ty != Tvoid)
560 return make_bool_binop(this, irs);
561 else
562 return build(COND_EXPR, type->toCtype(),
563 e1->toElem(irs), e2->toElem(irs), d_void_zero_node);
566 elem *
567 OrOrExp::toElem(IRState * irs)
569 if (e2->type->toBasetype()->ty != Tvoid)
570 return make_bool_binop(this, irs);
571 else
572 return build(COND_EXPR, type->toCtype(),
573 build1(TRUTH_NOT_EXPR, boolean_type_node, e1->toElem(irs)),
574 e2->toElem(irs), d_void_zero_node);
577 elem *
578 XorExp::toElem(IRState * irs) { return make_math_op(this, irs); }
579 elem *
580 OrExp::toElem(IRState * irs) { return make_math_op(this, irs); }
581 elem *
582 AndExp::toElem(IRState * irs) { return make_math_op(this, irs); }
583 elem *
584 UshrExp::toElem(IRState* irs) { return make_math_op(this, irs); }
585 elem *
586 ShrExp::toElem(IRState * irs) { return make_math_op(this, irs); }
587 elem *
588 ShlExp::toElem(IRState * irs) { return make_math_op(this, irs); }
590 elem *
591 ModExp::toElem(IRState * irs)
593 return make_math_op(this, irs);
595 elem *
596 DivExp::toElem(IRState * irs)
598 return make_math_op(this, irs);
600 elem *
601 MulExp::toElem(IRState * irs)
603 return make_math_op(this, irs);
606 static tree
607 one_elem_array(IRState * irs, Expression * value, tree & var_decl_out)
609 tree v = irs->maybeExprVar(value->toElem(irs), & var_decl_out);
610 return irs->darrayVal(value->type->arrayOf(), 1, irs->addressOf(v));
613 elem *
614 CatExp::toElem(IRState * irs)
616 Type * elem_type;
618 // One of the operands may be an element instead of an array.
619 // Logic copied from CatExp::semantic
621 Type * tb1 = e1->type->toBasetype();
622 Type * tb2 = e2->type->toBasetype();
624 if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
625 irs->typesCompatible(e2->type, tb1->nextOf()))
627 elem_type = tb1->nextOf();
628 else if ((tb2->ty == Tsarray || tb2->ty == Tarray) &&
629 irs->typesCompatible(e1->type, tb2->nextOf()))
631 elem_type = tb2->nextOf();
632 else
633 elem_type = tb1->nextOf();
636 // Flatten multiple concatenations
638 unsigned n_operands = 2;
639 unsigned n_args;
640 tree * args;
641 Array elem_vars;
642 tree result;
645 Expression * e = e1;
646 while (e->op == TOKcat) {
647 e = ((CatExp*) e)->e1;
648 n_operands += 1;
652 n_args = 1 + (n_operands > 2 ? 1 : 0) +
653 (n_operands * (irs->splitDynArrayVarArgs ? 2 : 1));
654 args = new tree[n_args];
655 args[0] = irs->typeinfoReference(type);
656 if (n_operands > 2)
657 args[1] = irs->integerConstant(n_operands, Type::tuns32);
659 unsigned ai = n_args - 1;
660 CatExp * ce = this;
662 while (ce) {
663 Expression *oe = ce->e2;
664 while (1)
666 tree array_exp;
667 if (irs->typesCompatible(oe->type->toBasetype(), elem_type))
669 tree elem_var = NULL_TREE;
670 array_exp = one_elem_array(irs, oe, elem_var);
671 if (elem_var)
672 elem_vars.push(elem_var);
674 else
675 array_exp = irs->toDArray(oe);
676 if (irs->splitDynArrayVarArgs)
678 array_exp = irs->maybeMakeTemp(array_exp);
679 args[ai--] = irs->darrayPtrRef(array_exp); // note: filling array
680 args[ai--] = irs->darrayLenRef(array_exp); // backwards, so ptr 1st
682 else
683 args[ai--] = array_exp;
685 if (ce) {
686 if (ce->e1->op != TOKcat) {
687 oe = ce->e1;
688 ce = NULL;
689 // finish with atomtic lhs
690 } else {
691 ce = (CatExp*) ce->e1;
692 break; // continue with lhs CatExp
694 } else
695 goto all_done;
698 all_done:
700 result = irs->libCall(n_operands > 2 ? LIBCALL_ARRAYCATNT : LIBCALL_ARRAYCATT,
701 n_args, args, type->toCtype());
703 for (unsigned i = 0; i < elem_vars.dim; ++i)
705 tree elem_var = (tree) elem_vars.data[i];
706 result = irs->binding(elem_var, result);
709 return result;
712 elem *
713 MinExp::toElem(IRState* irs)
715 // The front end has already taken care of pointer-int and pointer-pointer
716 return make_math_op(this, irs);
719 elem *
720 AddExp::toElem(IRState* irs)
722 TY ty1 = e1->type->toBasetype()->ty;
723 TY ty2 = e2->type->toBasetype()->ty;
725 if ((ty1 == Tarray || ty1 == Tsarray) &&
726 (ty2 == Tarray || ty2 == Tsarray) ) {
727 error("Array operations not implemented");
728 return irs->errorMark(type);
729 } else
730 // The front end has already taken care of (pointer + integer)
731 return make_math_op(this, irs);
734 tree chain_cvt(tree t, Type * typ, Array & casts, IRState * irs)
736 for (int i = casts.dim - 1; i >= 0; i--) {
737 t = irs->convertTo(t, typ, (Type *) casts.data[i]);
738 typ = (Type *) casts.data[i];
740 return t;
743 tree make_assign_math_op(BinExp * exp, IRState * irs)
745 Expression * e1_to_use;
746 Type * lhs_type = 0;
747 tree result;
748 TOK out_code;
749 Array lhs_casts; // no more than two casts?
751 switch (exp->op) {
752 case TOKaddass: out_code = TOKadd; break;
753 case TOKminass: out_code = TOKmin; break;
754 case TOKmulass: out_code = TOKmul; break;
755 case TOKxorass: out_code = TOKxor; break;
756 case TOKorass: out_code = TOKor; break;
757 case TOKandass: out_code = TOKand; break;
758 case TOKshlass: out_code = TOKshl; break;
759 case TOKushrass: out_code = TOKushr; break;
760 case TOKshrass: out_code = TOKshr; break;
761 case TOKmodass: out_code = TOKmod; break;
762 case TOKdivass: out_code = TOKdiv; break;
763 default:
764 abort();
767 e1_to_use = exp->e1;
768 lhs_type = e1_to_use->type;
769 while (e1_to_use->op == TOKcast) {
770 CastExp * cast_exp = (CastExp *) e1_to_use;
771 assert(irs->typesCompatible(cast_exp->type, cast_exp->to)); // %% check, basetype?
772 lhs_casts.push(cast_exp->to);
773 e1_to_use = cast_exp->e1;
776 tree tgt = stabilize_reference( irs->toElemLvalue(e1_to_use) );
777 tree lhs = chain_cvt(tgt, e1_to_use->type, lhs_casts, irs);
779 Type * src_type = lhs_type;
782 /* Determine the correct combined type from BinExp::typeCombine. */
783 TY ty = (TY) Type::impcnvResult[lhs_type->toBasetype()->ty][exp->e2->type->toBasetype()->ty];
784 if (ty != Terror)
785 src_type = Type::basic[ty];
787 if ((out_code == TOKmul || out_code == TOKdiv) && exp->e1->type->isimaginary())
789 assert( exp->e2->type->isfloating() );
790 if ( ! exp->e2->type->isimaginary() && ! exp->e2->type->iscomplex() )
792 assert( exp->e1->type->size() == exp->e2->type->size() );
793 src_type = exp->e1->type;
796 tree src = make_math_op(out_code, lhs, lhs_type,
797 exp->e2->toElem(irs), exp->e2->type,
798 src_type, irs);
799 result = build(MODIFY_EXPR, exp->type->toCtype(),
800 tgt, irs->convertForAssignment(src, src_type, e1_to_use->type));
802 return result;
805 elem *
806 XorAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
807 elem *
808 OrAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
809 elem *
810 AndAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
811 elem *
812 UshrAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
813 elem *
814 ShrAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
815 elem *
816 ShlAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
817 elem *
818 ModAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
819 elem *
820 DivAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
821 elem *
822 MulAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
824 elem *
825 CatAssignExp::toElem(IRState * irs) {
826 tree args[3];
827 Type * elem_type = e1->type->toBasetype()->nextOf()->toBasetype();
828 LibCall lib_call;
829 AddrOfExpr aoe;
831 args[0] = irs->typeinfoReference( type );
832 args[1] = irs->addressOf( irs->toElemLvalue(e1) );
834 gcc_assert(elem_type->ty != Tbit);
836 if (irs->typesCompatible(elem_type, e2->type->toBasetype())) {
837 // append an element
838 args[2] = aoe.set(irs, e2->toElem(irs) );
839 lib_call = LIBCALL_ARRAYAPPENDCTP;
840 } else {
841 // append an array
842 args[2] = irs->toDArray(e2);
843 lib_call = LIBCALL_ARRAYAPPENDT;
845 return aoe.finish(irs, irs->libCall(lib_call, 3, args, type->toCtype()));
848 elem *
849 MinAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
850 elem *
851 AddAssignExp::toElem(IRState * irs) { return make_assign_math_op(this, irs); }
854 void do_array_set(IRState * irs, tree in_ptr, tree in_val, tree in_cnt) {
855 irs->startBindings(); // %%maybe not
857 tree count_var = irs->localVar(Type::tsize_t);
858 tree ptr_var = irs->localVar(TREE_TYPE(in_ptr));
859 tree val_var = NULL_TREE;
860 tree value_to_use = NULL_TREE;
862 DECL_INITIAL(count_var) = in_cnt;
863 DECL_INITIAL(ptr_var) = in_ptr;
865 irs->expandDecl(count_var);
866 irs->expandDecl(ptr_var);
868 if (irs->isFreeOfSideEffects(in_val)) {
869 value_to_use = in_val;
870 } else {
871 val_var = irs->localVar(TREE_TYPE(in_val));
872 DECL_INITIAL(val_var) = in_val;
873 irs->expandDecl(val_var);
874 value_to_use = val_var;
877 irs->startLoop(NULL);
879 irs->continueHere();
881 irs->exitIfFalse( build(NE_EXPR, boolean_type_node, integer_zero_node, count_var) );
883 irs->doExp( build(MODIFY_EXPR, void_type_node, irs->indirect(ptr_var), value_to_use));
884 irs->doExp( build(MODIFY_EXPR, void_type_node, ptr_var,
885 build(PLUS_EXPR, TREE_TYPE(ptr_var), ptr_var,
886 TYPE_SIZE_UNIT(TREE_TYPE(TREE_TYPE(ptr_var))))) );
887 irs->doExp( build(MODIFY_EXPR, void_type_node, count_var,
888 build(MINUS_EXPR, TREE_TYPE(count_var), count_var, integer_one_node)) );
890 irs->endLoop();
892 irs->endBindings();
896 // Create a tree node to set multiple elements to a single value
897 tree array_set_expr(IRState * irs, tree ptr, tree src, tree count) {
898 #if D_GCC_VER < 40
899 tree exp = build( (enum tree_code) D_ARRAY_SET_EXPR, void_type_node,
900 ptr, src, count);
901 TREE_SIDE_EFFECTS( exp ) = 1;
902 return exp;
903 #else
904 irs->pushStatementList();
905 do_array_set(irs, ptr, src, count);
906 return irs->popStatementList();
907 #endif
910 elem *
911 AssignExp::toElem(IRState* irs) {
912 // First, handle special assignment semantics
913 if (e1->op == TOKarraylength) {
914 // Assignment to an array's length property; resize the array.
916 Type * array_type;
917 Type * elem_type;
918 tree args[5];
919 tree array_exp;
920 tree result;
923 Expression * ae = ((ArrayLengthExp *) e1)->e1;
924 array_type = ae->type;
925 elem_type = ae->type->toBasetype()->nextOf(); // don't want ->toBasetype for the element type
926 array_exp = irs->addressOf( ae->toElem( irs ));
929 #if ! V2
930 gcc_assert(! elem_type->isbit());
931 #endif
933 args[0] = irs->typeinfoReference(array_type);
934 args[1] = irs->convertTo(e2, Type::tsize_t);
935 args[2] = array_exp;
937 LibCall lib_call = elem_type->isZeroInit() ?
938 LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
940 result = irs->libCall(lib_call, 3, args);
941 result = irs->darrayLenRef( result );
943 return result;
944 } else if (e1->op == TOKslice) {
945 Type * elem_type = e1->type->toBasetype()->nextOf()->toBasetype();
947 gcc_assert(elem_type->ty != Tbit);
949 if (irs->typesCompatible(elem_type, e2->type->toBasetype())) {
950 // Set a range of elements to one value.
952 // %% This is used for initing on-stack static arrays..
953 // should optimize with memset if possible
954 // %% vararg issues
956 tree dyn_array_exp = irs->maybeMakeTemp( e1->toElem(irs) );
957 #if V2
958 if (op != TOKblit)
960 Type * t = elem_type;
961 while (t->ty == Tsarray)
962 t = t->nextOf()->toBasetype();
963 if (t->ty == Tstruct)
965 StructDeclaration *sd = ((TypeStruct *)elem_type)->sym;
966 if (sd->postblit)
968 tree e;
969 AddrOfExpr aoe;
970 tree args[4];
971 args[0] = irs->darrayPtrRef(dyn_array_exp);
972 args[1] = aoe.set(irs, e2->toElem(irs));
973 args[2] = irs->darrayLenRef(dyn_array_exp);
974 args[3] = irs->typeinfoReference(elem_type);
975 e = irs->libCall(op == TOKconstruct ?
976 LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN,
977 4, args);
978 e = irs->compound(aoe.finish(irs, e), dyn_array_exp);
979 return e;
984 #endif
986 tree set_exp = array_set_expr( irs, irs->darrayPtrRef(dyn_array_exp),
987 e2->toElem(irs), irs->darrayLenRef(dyn_array_exp));
988 return irs->compound(set_exp, dyn_array_exp);
989 } else {
990 bool postblit = false;
991 #if V2
992 Type * t = elem_type;
993 while (t->ty == Tsarray)
994 t = t->nextOf()->toBasetype();
995 if (t->ty == Tstruct)
997 StructDeclaration *sd = ((TypeStruct *)elem_type)->sym;
998 if (sd->postblit)
999 postblit = true;
1002 if (postblit && op != TOKblit)
1004 tree args[3] = {
1005 irs->typeinfoReference(elem_type),
1006 irs->toDArray(e1),
1007 irs->toDArray(e2)
1009 return irs->libCall(op == TOKconstruct ?
1010 LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN,
1011 3, args, type->toCtype());
1013 else
1014 #endif
1015 if (global.params.useArrayBounds)
1017 tree args[3] = {
1018 irs->integerConstant(elem_type->size(), Type::tsize_t),
1019 irs->toDArray(e2),
1020 irs->toDArray(e1) };
1021 return irs->libCall(LIBCALL_ARRAYCOPY, 3, args, type->toCtype());
1023 else
1025 tree array[2] = {
1026 irs->maybeMakeTemp( irs->toDArray(e1) ),
1027 irs->toDArray(e2) };
1028 tree t_memcpy = built_in_decls[BUILT_IN_MEMCPY];
1029 tree result;
1030 tree size;
1032 size = build(MULT_EXPR, size_type_node,
1033 convert(size_type_node, irs->darrayLenRef(array[0])),
1034 size_int(elem_type->size()));
1035 size = fold( size );
1037 result = irs->buildCall( TREE_TYPE(TREE_TYPE( t_memcpy )),
1038 irs->addressOf( t_memcpy ),
1039 tree_cons( NULL_TREE, irs->darrayPtrRef(array[0]),
1040 tree_cons( NULL_TREE, irs->darrayPtrRef(array[1]),
1041 tree_cons( NULL_TREE, size, NULL_TREE))));
1043 return irs->compound( result, array[0], type->toCtype() );
1046 } else {
1047 // Simple assignment
1049 tree lhs = irs->toElemLvalue(e1);
1050 tree result = build(MODIFY_EXPR, type->toCtype(),
1051 lhs, irs->convertForAssignment(e2, e1->type));
1053 return result;
1057 elem *
1058 PostExp::toElem(IRState* irs)
1060 enum tree_code tc;
1061 if (op == TOKplusplus)
1062 tc = POSTINCREMENT_EXPR;
1063 else if (op == TOKminusminus)
1064 tc = POSTDECREMENT_EXPR;
1065 else
1067 gcc_unreachable();
1068 return irs->errorMark(type);
1070 tree result = build(tc, type->toCtype(),
1071 irs->toElemLvalue(e1), e2->toElem(irs));
1072 TREE_SIDE_EFFECTS(result) = 1;
1073 return result;
1076 elem *
1077 IndexExp::toElem(IRState* irs)
1079 Type * array_type = e1->type->toBasetype();
1081 if (array_type->ty != Taarray) {
1082 ArrayScope aryscp(irs, lengthVar, loc);
1083 /* arrayElemRef will call aryscp.finish. This result
1084 of this function may be used as an lvalue and we
1085 do not want it to be a BIND_EXPR. */
1086 return irs->arrayElemRef( this, & aryscp );
1087 } else {
1088 Type * key_type = ((TypeAArray *) array_type)->index->toBasetype();
1089 AddrOfExpr aoe;
1090 tree args[4];
1091 tree t;
1092 args[0] = e1->toElem(irs);
1093 args[1] = irs->typeinfoReference(key_type);
1094 args[2] = irs->integerConstant( array_type->nextOf()->size(), Type::tsize_t );
1095 args[3] = aoe.set(irs, irs->convertTo( e2, key_type ) );
1096 t = irs->libCall(LIBCALL_AAGETRVALUEP, 4, args, type->pointerTo()->toCtype());
1097 t = aoe.finish(irs, t);
1098 if (global.params.useArrayBounds) {
1099 t = save_expr(t);
1100 t = build(COND_EXPR, TREE_TYPE(t), t, t,
1101 irs->assertCall(loc, LIBCALL_ARRAY_BOUNDS));
1103 t = irs->indirect(t, type->toCtype());
1104 return t;
1108 elem *
1109 CommaExp::toElem(IRState * irs)
1111 // CommaExp is used with DotTypeExp..?
1112 if (e1->op == TOKdottype && e2->op == TOKvar) {
1113 VarExp * ve = (VarExp *) e2;
1114 VarDeclaration * vd;
1115 FuncDeclaration * fd;
1116 /* Handle references to static variable and functions. Otherwise,
1117 just let the DotTypeExp report an error. */
1118 if (( (vd = ve->var->isVarDeclaration()) && ! vd->needThis() ) ||
1119 ( (fd = ve->var->isFuncDeclaration()) && ! fd->isThis() ))
1120 return e2->toElem(irs);
1122 tree t1 = e1->toElem( irs );
1123 tree t2 = e2->toElem( irs );
1124 return build(COMPOUND_EXPR, type->toCtype(), t1, t2);
1127 elem *
1128 ArrayLengthExp::toElem(IRState * irs)
1130 if (e1->type->toBasetype()->ty == Tarray) {
1131 return irs->darrayLenRef(e1->toElem(irs));
1132 } else {
1133 // Tsarray case seems to be handled by front-end
1135 error("unexpected type for array length: %s", type->toChars());
1136 return irs->errorMark(type);
1140 elem *
1141 SliceExp::toElem(IRState * irs)
1143 // This function assumes that the front end casts the result to a dynamic array.
1144 assert(type->toBasetype()->ty == Tarray);
1146 // Use convert-to-dynamic-array code if possible
1147 if (e1->type->toBasetype()->ty == Tsarray && ! upr && ! lwr)
1148 return irs->convertTo(e1->toElem(irs), e1->type, type);
1150 Type * orig_array_type = e1->type->toBasetype();
1152 tree orig_array_expr = NULL;
1153 tree orig_pointer_expr;
1154 tree final_len_expr = NULL;
1155 tree final_ptr_expr = NULL;
1156 tree array_len_expr = NULL;
1157 tree lwr_tree = NULL;
1159 ArrayScope aryscp(irs, lengthVar, loc);
1161 orig_array_expr = aryscp.setArrayExp( e1->toElem(irs), e1->type );
1162 orig_array_expr = irs->maybeMakeTemp( orig_array_expr );
1163 // specs don't say bounds if are checked for error or clipped to current size
1165 // Get the data pointer for static and dynamic arrays
1166 orig_pointer_expr = irs->convertTo(orig_array_expr, orig_array_type,
1167 orig_array_type->nextOf()->pointerTo());
1169 final_ptr_expr = orig_pointer_expr;
1171 // orig_array_expr is already a save_expr if necessary, so
1172 // we don't make array_len_expr a save_expr which is, at most,
1173 // a COMPONENT_REF on top of orig_array_expr.
1174 if ( orig_array_type->ty == Tarray ) {
1175 array_len_expr = irs->darrayLenRef( orig_array_expr );
1176 } else if ( orig_array_type->ty == Tsarray ) {
1177 array_len_expr = ((TypeSArray *) orig_array_type)->dim->toElem(irs);
1178 } else {
1179 // array_len_expr == NULL indicates no bounds check is possible
1182 if (lwr) {
1183 lwr_tree = lwr->toElem(irs);
1184 if (integer_zerop(lwr_tree))
1185 lwr_tree = NULL_TREE;
1187 if (upr) {
1188 final_len_expr = upr->toElem(irs);
1189 if (global.params.useArrayBounds && array_len_expr) {
1190 final_len_expr = irs->maybeMakeTemp(final_len_expr);
1191 final_len_expr = irs->checkedIndex(loc, final_len_expr, array_len_expr, true);
1193 if (lwr_tree) {
1194 lwr_tree = irs->maybeMakeTemp(lwr_tree);
1195 // %% type
1196 final_len_expr = build(MINUS_EXPR, TREE_TYPE(final_len_expr), final_len_expr, lwr_tree);
1198 } else {
1199 // If this is the case, than there is no lower bound specified and
1200 // there is no need to subtract.
1201 switch (orig_array_type->ty) {
1202 case Tarray:
1203 final_len_expr = irs->darrayLenRef(orig_array_expr);
1204 break;
1205 case Tsarray:
1206 final_len_expr = ((TypeSArray *) orig_array_type)->dim->toElem(irs);
1207 break;
1208 default:
1209 ::error("Attempt to take length of something that was not an array");
1210 return irs->errorMark(type);
1213 if (lwr_tree) {
1214 if (global.params.useArrayBounds && array_len_expr) { // %% && ! is zero
1215 lwr_tree = irs->maybeMakeTemp(lwr_tree);
1216 lwr_tree = irs->checkedIndex(loc, lwr_tree, array_len_expr, true); // lower bound can equal length
1219 #if ! V2
1220 gcc_assert(! orig_array_type->next->isbit());
1221 #endif
1223 final_ptr_expr = irs->pointerIntSum(irs->pvoidOkay(final_ptr_expr), lwr_tree);
1224 final_ptr_expr = irs->nop(final_ptr_expr, TREE_TYPE( orig_pointer_expr ));
1227 return aryscp.finish( irs->darrayVal(type->toCtype(), final_len_expr, final_ptr_expr) );
1230 elem *
1231 CastExp::toElem(IRState * irs)
1233 return irs->convertTo(e1, to);
1236 static tree
1237 make_aa_del(IRState * irs, Expression * e_array, Expression * e_index)
1239 tree args[3];
1240 Type * key_type = ((TypeAArray *) e_array->type->toBasetype())->index->toBasetype();
1241 AddrOfExpr aoe;
1243 args[0] = e_array->toElem(irs);
1244 args[1] = irs->typeinfoReference(key_type);
1245 args[2] = aoe.set(irs, irs->convertTo( e_index, key_type ));
1246 return aoe.finish(irs, irs->libCall(LIBCALL_AADELP, 3, args) );
1249 elem *
1250 DeleteExp::toElem(IRState* irs)
1252 // Does this look like an associative array delete?
1253 if (e1->op == TOKindex &&
1254 ((IndexExp*)e1)->e1->type->toBasetype()->ty == Taarray) {
1256 if (! global.params.useDeprecated)
1257 error("delete aa[key] deprecated, use aa.remove(key)", e1->toChars());
1259 Expression * e_array = ((BinExp *) e1)->e1;
1260 Expression * e_index = ((BinExp *) e1)->e2;
1262 // Check that the array is actually an associative array
1263 if (e_array->type->toBasetype()->ty == Taarray)
1264 return make_aa_del(irs, e_array, e_index);
1267 // Otherwise, this is normal delete
1268 LibCall lib_call;
1269 tree t = e1->toElem(irs);
1270 Type * base_type = e1->type->toBasetype();
1272 switch (base_type->ty) {
1273 case Tclass:
1275 VarDeclaration * v;
1276 bool is_intfc =
1277 base_type->isClassHandle()->isInterfaceDeclaration() != NULL;
1279 if (e1->op == TOKvar &&
1280 ( v = ((VarExp*) e1)->var->isVarDeclaration() ) && v->onstack)
1281 lib_call = is_intfc ?
1282 LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
1283 else
1284 lib_call = is_intfc ? LIBCALL_DELINTERFACE : LIBCALL_DELCLASS;
1286 break;
1287 case Tarray: lib_call = LIBCALL_DELARRAY; break;
1288 case Tpointer: lib_call = LIBCALL_DELMEMORY; break;
1289 default:
1290 error("don't know how to delete %s", e1->toChars());
1291 return irs->errorMark(type);
1294 if (lib_call != LIBCALL_CALLFINALIZER && lib_call != LIBCALL_CALLINTERFACEFINALIZER)
1295 t = irs->addressOf( t );
1297 return irs->libCall(lib_call, 1, & t);
1300 elem *
1301 RemoveExp::toElem(IRState * irs)
1303 Expression * e_array = e1;
1304 Expression * e_index = e2;
1306 // Check that the array is actually an associative array
1307 if (e_array->type->toBasetype()->ty == Taarray) {
1308 return make_aa_del(irs, e_array, e_index);
1309 } else {
1310 error("%s is not an associative array", e_array->toChars());
1311 return irs->errorMark(type);
1315 elem *
1316 BoolExp::toElem(IRState * irs)
1318 return d_convert_basic(type->toCtype(), irs->convertForCondition(e1));
1321 elem *
1322 NotExp::toElem(IRState * irs)
1324 // %% doc: need to convert to boolean type or this will fail.
1325 tree t = build1(TRUTH_NOT_EXPR, boolean_type_node,
1326 irs->convertForCondition(e1));
1327 return convert(type->toCtype(), t);
1330 elem *
1331 ComExp::toElem(IRState * irs)
1333 return build1(BIT_NOT_EXPR, type->toCtype(), e1->toElem( irs ));
1336 elem *
1337 NegExp::toElem(IRState * irs)
1339 // %% GCC B.E. won't optimize (NEGATE_EXPR (INTEGER_CST ..))..
1340 // %% is type correct?
1341 return build1(NEGATE_EXPR, type->toCtype(), e1->toElem(irs));
1344 elem *
1345 PtrExp::toElem(IRState * irs)
1347 /* add this from c-typeck.c:
1348 TREE_READONLY (ref) = TYPE_READONLY (t);
1349 TREE_SIDE_EFFECTS (ref)
1350 = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
1351 TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
1354 /* Produce better code by converting *(#rec + n) to
1355 COMPONENT_REFERENCE. Otherwise, the variable will always be
1356 allocated in memory because its address is taken. */
1357 Type * rec_type = 0;
1358 target_size_t the_offset;
1359 tree rec_tree;
1361 if (e1->op == TOKadd) {
1362 BinExp * add_exp = (BinExp *) e1;
1363 if (add_exp->e1->op == TOKaddress &&
1364 add_exp->e2->isConst() && add_exp->e2->type->isintegral()) {
1365 Expression * rec_exp = ((AddrExp*) add_exp->e1)->e1;
1366 rec_type = rec_exp->type->toBasetype();
1367 rec_tree = rec_exp->toElem(irs);
1368 the_offset = add_exp->e2->toUInteger();
1370 } else if (e1->op == TOKsymoff) {
1371 // is this ever not a VarDeclaration?
1372 SymOffExp * sym_exp = (SymOffExp *) e1;
1373 if ( ! irs->isDeclarationReferenceType(sym_exp->var)) {
1374 rec_type = sym_exp->var->type->toBasetype();
1375 VarDeclaration * v = sym_exp->var->isVarDeclaration();
1376 if (v)
1377 rec_tree = irs->var(v);
1378 else
1379 rec_tree = sym_exp->var->toSymbol()->Stree;
1380 the_offset = sym_exp->offset;
1382 // otherwise, no real benefit?
1385 if (rec_type && rec_type->ty == Tstruct) {
1386 StructDeclaration * sd = ((TypeStruct *)rec_type)->sym;
1387 for (unsigned i = 0; i < sd->fields.dim; i++) {
1388 VarDeclaration * field = (VarDeclaration *) sd->fields.data[i];
1389 if (field->offset == the_offset &&
1390 irs->typesSame(field->type, this->type)) {
1391 if (irs->isErrorMark(rec_tree))
1392 return rec_tree; // backend will ICE otherwise
1393 return irs->component(rec_tree, field->toSymbol()->Stree);
1394 } else if (field->offset > the_offset) {
1395 break;
1400 tree e = irs->indirect(e1->toElem(irs), type->toCtype());
1401 if (irs->inVolatile())
1402 TREE_THIS_VOLATILE( e ) = 1;
1403 return e;
1406 elem *
1407 AddrExp::toElem(IRState * irs)
1409 return irs->nop(irs->addressOf(e1->toElem(irs)), type->toCtype());
1412 elem *
1413 CallExp::toElem(IRState* irs)
1415 tree t = irs->call(e1, arguments);
1416 // Some library calls are defined to return a generic type.
1417 // this->type is the real type. (See crash2.d)
1418 TREE_TYPE(t) = type->toCtype();
1419 return t;
1422 elem *
1423 Expression::toElem(IRState* irs)
1425 error("abstract Expression::toElem called");
1426 return irs->errorMark(type);
1429 elem *
1430 DotTypeExp::toElem(IRState *irs)
1432 // The only case in which this seems to be a valid expression is when
1433 // it is used to specify a non-virtual call ( SomeClass.func(...) ).
1434 // This case is handled in IRState::objectInstanceMethod.
1436 error("cannot use \"%s\" as an expression", toChars());
1438 // Can cause ICEs later; should just exit now.
1439 return irs->errorMark(type);
1442 // The result will probably just be converted to a CONSTRUCTOR for a Tdelegate struct
1443 elem *
1444 DelegateExp::toElem(IRState* irs)
1446 Type * t = e1->type->toBasetype();
1447 if (t->ty == Tclass || t->ty == Tstruct) {
1448 // %% Need to see if DotVarExp ever has legitimate
1449 // <aggregate>.<static method>. If not, move this test
1450 // to objectInstanceMethod.
1451 if (! func->isThis())
1452 error("delegates are only for non-static functions");
1453 return irs->objectInstanceMethod(e1, func, type);
1454 } else {
1455 assert(func->isNested() || func->isThis());
1456 return irs->methodCallExpr(irs->functionPointer(func),
1457 func->isNested() ?
1458 #if D_NO_TRAMPOLINES
1459 irs->getFrameForFunction(func)
1460 #else
1461 d_null_pointer
1462 #endif
1463 : e1->toElem(irs), type);
1467 elem *
1468 DotVarExp::toElem(IRState * irs)
1470 FuncDeclaration * func_decl;
1471 VarDeclaration * var_decl;
1472 Type * obj_basetype = e1->type->toBasetype();
1473 TY obj_basetype_ty = obj_basetype->ty;
1474 switch (obj_basetype_ty) {
1475 case Tpointer:
1476 if (obj_basetype->nextOf()->toBasetype()->ty != Tstruct) {
1477 break;
1479 // drop through
1480 case Tstruct:
1481 // drop through
1482 case Tclass:
1483 if ( (func_decl = var->isFuncDeclaration()) ) {
1484 // if Tstruct, objInstanceMethod will use the address of e1
1485 return irs->objectInstanceMethod(e1, func_decl, type);
1486 } else if ( (var_decl = var->isVarDeclaration()) ) {
1487 if (var_decl->storage_class & STCfield) {
1488 tree this_tree = e1->toElem(irs);
1489 if ( obj_basetype_ty != Tstruct )
1490 this_tree = irs->indirect(this_tree);
1491 return irs->component(this_tree, var_decl->toSymbol()->Stree);
1492 } else {
1493 return irs->var(var_decl);
1495 } else {
1496 // error below
1498 break;
1499 default:
1500 break;
1502 ::error("Don't know how to handle %s", toChars());
1503 return irs->errorMark(type);
1506 elem *
1507 AssertExp::toElem(IRState* irs)
1509 // %% todo: Do we call a Tstruct's invariant if
1510 // e1 is a pointer to the struct?
1511 if (global.params.useAssert) {
1512 Type * base_type = e1->type->toBasetype();
1513 TY ty = base_type->ty;
1514 tree assert_call = msg ?
1515 irs->assertCall(loc, msg) : irs->assertCall(loc);
1517 if (ty == Tclass) {
1518 ClassDeclaration * cd = base_type->isClassHandle();
1519 tree arg = e1->toElem(irs);
1520 if (cd->isCOMclass())
1522 return build(COND_EXPR, void_type_node,
1523 irs->boolOp(NE_EXPR, arg, d_null_pointer),
1524 d_void_zero_node, assert_call);
1526 else if (cd->isInterfaceDeclaration())
1528 arg = irs->convertTo(arg, base_type, irs->getObjectType());
1530 return irs->libCall(LIBCALL_INVARIANT, 1, & arg); // this does a null pointer check
1531 } else {
1532 // build: ( (bool) e1 ? (void)0 : _d_assert(...) )
1533 // or: ( e1 != null ? (void)0 : _d_assert(...), e1._invariant() )
1534 tree result;
1535 tree invc = NULL_TREE;
1536 tree e1_t = e1->toElem(irs);
1538 if (ty == Tpointer) {
1539 Type * sub_type = base_type->nextOf()->toBasetype();
1540 if (sub_type->ty == Tstruct) {
1541 AggregateDeclaration * agg_decl = ((TypeStruct *) sub_type)->sym;
1542 if (agg_decl->inv) {
1543 Array args;
1544 e1_t = irs->maybeMakeTemp(e1_t);
1545 invc = irs->call(agg_decl->inv, e1_t, & args );
1550 result = build(COND_EXPR, void_type_node,
1551 irs->convertForCondition( e1_t, e1->type ),
1552 d_void_zero_node, assert_call);
1553 if (invc)
1554 result = build(COMPOUND_EXPR, void_type_node, result, invc);
1555 return result;
1557 } else
1558 return d_void_zero_node;
1561 elem *
1562 DeclarationExp::toElem(IRState* irs)
1564 // VarDeclaration::toObjFile was modified to call d_gcc_emit_local_variable
1565 // if needed. This assumes irs == g.irs
1566 #if D_GCC_VER < 40
1567 tree rtl_expr = expand_start_stmt_expr(0);
1568 declaration->toObjFile(false);
1569 expand_end_stmt_expr (rtl_expr);
1570 return rtl_expr;
1571 #else
1572 irs->pushStatementList();
1573 declaration->toObjFile(false);
1574 return irs->popStatementList();
1575 #endif
1578 void
1579 d_gcc_emit_local_variable(VarDeclaration * v)
1581 g.irs->emitLocalVar(v);
1584 bool
1585 d_gcc_supports_weak()
1587 return SUPPORTS_WEAK;
1590 // %% check calling this directly?
1591 elem *
1592 FuncExp::toElem(IRState * irs)
1594 fd->toObjFile(false);
1596 Type * func_type = type->toBasetype();
1598 if (func_type->ty == Tpointer)
1599 func_type = func_type->nextOf()->toBasetype();
1601 switch (func_type->ty) {
1602 case Tfunction:
1603 return irs->nop(irs->addressOf(fd), type->toCtype());
1604 case Tdelegate:
1605 return irs->methodCallExpr(irs->functionPointer(fd), // trampoline or not
1606 #if D_NO_TRAMPOLINES
1607 irs->getFrameForFunction(fd),
1608 #else
1609 convert(ptr_type_node, integer_one_node),
1610 #endif
1611 type);
1612 default:
1613 ::error("Unexpected FunExp type");
1614 return irs->errorMark(type);
1617 // If nested, this will be a trampoline...
1620 elem *
1621 HaltExp::toElem(IRState* irs)
1623 // Needs improvement. Avoid library calls if possible..
1624 tree t_abort = built_in_decls[BUILT_IN_ABORT];
1625 return irs->buildCall( TREE_TYPE(TREE_TYPE(t_abort)),
1626 irs->addressOf(t_abort), NULL_TREE);
1629 #if V2
1630 elem *
1631 SymbolExp::toElem(IRState * irs)
1633 if (op == TOKvar) {
1634 if (var->storage_class & STCfield) {
1635 /*::*/error("Need 'this' to access member %s", var->ident->string);
1636 return irs->errorMark(type);
1639 // For variables that are references (currently only out/inout arguments;
1640 // objects don't count), evaluating the variable means we want what it refers to.
1642 // TODO: is this ever not a VarDeclaration; (four sequences like this...)
1643 VarDeclaration * v = var->isVarDeclaration();
1644 tree e;
1645 if (v)
1646 e = irs->var(v);
1647 else
1648 e = var->toSymbol()->Stree;
1650 if ( irs->isDeclarationReferenceType(var) ) {
1651 e = irs->indirect(e, var->type->toCtype());
1652 if (irs->inVolatile()) {
1653 TREE_THIS_VOLATILE(e) = 1;
1655 } else {
1656 if (irs->inVolatile()) {
1657 e = irs->addressOf(e);
1658 TREE_THIS_VOLATILE(e) = 1;
1659 e = irs->indirect(e);
1660 TREE_THIS_VOLATILE(e) = 1;
1663 return e;
1664 } else if (op == TOKsymoff) {
1665 target_size_t offset = ((SymOffExp *) this)->offset;
1667 VarDeclaration * v = var->isVarDeclaration();
1668 tree a;
1669 if (v)
1670 a = irs->var(v);
1671 else
1672 a = var->toSymbol()->Stree;
1674 if ( irs->isDeclarationReferenceType(var) )
1675 assert(POINTER_TYPE_P(TREE_TYPE(a)));
1676 else
1677 a = irs->addressOf(a);
1679 if (! offset)
1680 return convert(type->toCtype(), a);
1682 tree b = irs->integerConstant(offset, Type::tsize_t);
1683 return build(PLUS_EXPR, type->toCtype(), a, b) ;
1685 else
1686 gcc_assert(op == TOKvar || op == TOKsymoff);
1687 return error_mark_node;
1689 #else
1690 elem *
1691 VarExp::toElem(IRState* irs)
1693 if (var->storage_class & STCfield) {
1694 /*::*/error("Need 'this' to access member %s", var->ident->string);
1695 return irs->errorMark(type);
1698 // For variables that are references (currently only out/inout arguments;
1699 // objects don't count), evaluating the variable means we want what it refers to.
1700 //tree e = irs->var(var);
1701 VarDeclaration * v = var->isVarDeclaration();
1702 tree e;
1703 if (v)
1704 e = irs->var(v);
1705 else
1706 e = var->toSymbol()->Stree;
1708 if ( irs->isDeclarationReferenceType(var) ) {
1709 e = irs->indirect(e, var->type->toCtype());
1710 if (irs->inVolatile()) {
1711 TREE_THIS_VOLATILE(e) = 1;
1713 } else {
1714 if (irs->inVolatile()) {
1715 e = irs->addressOf(e);
1716 TREE_THIS_VOLATILE(e) = 1;
1717 e = irs->indirect(e);
1718 TREE_THIS_VOLATILE(e) = 1;
1721 return e;
1724 elem *
1725 SymOffExp::toElem(IRState * irs) {
1726 //tree a = irs->var(var);
1727 tree a;
1728 VarDeclaration * v = var->isVarDeclaration();
1729 if (v)
1730 a = irs->var(v);
1731 else
1732 a = var->toSymbol()->Stree;
1734 if ( irs->isDeclarationReferenceType(var) )
1735 assert(POINTER_TYPE_P(TREE_TYPE(a)));
1736 else
1737 a = irs->addressOf(var);
1739 if (! offset)
1740 return convert(type->toCtype(), a);
1742 tree b = irs->integerConstant(offset, Type::tsize_t);
1743 return build(PLUS_EXPR, type->toCtype(), a, b) ;
1745 #endif
1747 bool
1748 isClassNestedIn(ClassDeclaration *inner, ClassDeclaration *outer)
1750 // not implemented yet
1751 return false;
1754 static FuncDeclaration *
1755 isClassNestedInFunction(ClassDeclaration * cd)
1757 while (cd) {
1758 if (cd->isNested()) {
1759 Dsymbol * s = cd->toParent2();
1760 FuncDeclaration * fd = s->isFuncDeclaration();
1762 if (fd)
1763 return fd;
1764 else {
1765 cd = s->isClassDeclaration();
1766 assert(cd);
1768 } else
1769 break;
1771 return NULL;
1776 findThis
1778 Starting from the current function, try to find a suitable value of
1779 'this' in nested functions and (not implemented yet:) nested class
1780 instances.
1782 A suitable 'this' value is an instance of target_cd or a class that
1783 has target_cd as a base.
1786 static tree
1787 findThis(IRState * irs, ClassDeclaration * target_cd)
1789 FuncDeclaration * fd = irs->func;
1791 while (fd) {
1792 AggregateDeclaration * fd_ad;
1793 ClassDeclaration * fd_cd;
1795 if ((fd_ad = fd->isThis()) &&
1796 (fd_cd = fd_ad->isClassDeclaration())) {
1797 if (target_cd == fd_cd) {
1798 return irs->var(fd->vthis);
1799 } else if (target_cd->isBaseOf(fd_cd, NULL)) {
1800 assert(fd->vthis); // && fd->vthis->csym->Stree
1801 return irs->convertTo(irs->var(fd->vthis),
1802 fd_cd->type, target_cd->type);
1803 } else if (isClassNestedIn(fd_cd, target_cd)) {
1804 // not implemented
1805 assert(0);
1806 } else {
1807 fd = isClassNestedInFunction(fd_cd);
1809 } else if (fd->isNested()) {
1810 fd = fd->toParent2()->isFuncDeclaration();
1811 } else
1812 fd = NULL;
1814 return NULL_TREE;
1817 elem *
1818 NewExp::toElem(IRState * irs)
1820 Type * base_type = newtype->toBasetype();
1821 tree result;
1823 if (allocator)
1824 assert(newargs);
1826 switch (base_type->ty) {
1827 case Tclass:
1829 TypeClass * class_type = (TypeClass *) base_type;
1830 ClassDeclaration * class_decl = class_type->sym;
1832 tree new_call;
1833 tree setup_exp = NULL_TREE;
1834 // type->toCtype() is a REFERENCE_TYPE; we want the RECORD_TYPE
1835 tree rec_type = TREE_TYPE( class_type->toCtype() );
1837 // Allocation call (custom allocator or _d_newclass)
1838 if (onstack) {
1839 tree stack_var = irs->localVar( rec_type );
1840 irs->expandDecl(stack_var);
1841 new_call = irs->addressOf(stack_var);
1842 setup_exp = build(MODIFY_EXPR, rec_type,
1843 irs->indirect(new_call, rec_type),
1844 class_decl->toInitializer()->Stree);
1845 } else if (allocator) {
1846 new_call = irs->call(allocator, newargs);
1847 new_call = save_expr( new_call );
1848 // copy memory...
1849 setup_exp = build(MODIFY_EXPR, rec_type,
1850 irs->indirect(new_call, rec_type),
1851 class_decl->toInitializer()->Stree);
1852 } else {
1853 tree arg = irs->addressOf( class_decl->toSymbol()->Stree );
1854 new_call = irs->libCall(LIBCALL_NEWCLASS, 1, & arg);
1857 if (class_type->sym->isNested()) {
1858 tree vthis_value = NULL_TREE;
1859 tree vthis_field = class_type->sym->vthis->toSymbol()->Stree;
1861 if (thisexp) {
1862 ClassDeclaration *thisexp_cd = thisexp->type->isClassHandle();
1863 Dsymbol *outer = class_decl->toParent2();
1864 target_ptrdiff_t offset = 0;
1866 vthis_value = thisexp->toElem(irs);
1867 if (outer != thisexp_cd) {
1868 ClassDeclaration * outer_cd = outer->isClassDeclaration();
1869 int i = outer_cd->isBaseOf(thisexp_cd, & offset);
1870 assert(i);
1871 // could just add offset
1872 vthis_value = irs->convertTo(vthis_value, thisexp->type, outer_cd->type);
1874 } else {
1875 Dsymbol *outer = class_decl->toParent2();
1876 ClassDeclaration *cd_outer = outer->isClassDeclaration();
1877 FuncDeclaration *fd_outer = outer->isFuncDeclaration();
1879 if (cd_outer) {
1880 vthis_value = findThis(irs, cd_outer);
1881 if (vthis_value == NULL_TREE)
1882 error("outer class %s 'this' needed to 'new' nested class %s",
1883 cd_outer->ident->string, class_decl->ident->string);
1884 } else if (fd_outer) {
1885 /* If a class nested in a function has no methods
1886 and there are no other nested functions,
1887 lower_nested_functions is never called and any
1888 STATIC_CHAIN_EXPR created here will never be
1889 translated. Use a null pointer for the link in
1890 this case. */
1891 if (
1892 #if V2
1893 fd_outer->closureVars.dim ||
1894 irs->getFrameInfo(fd_outer)->creates_closure
1895 #else
1896 fd_outer->nestedFrameRef
1897 #endif
1899 vthis_value = irs->getFrameForNestedClass(class_decl); // %% V2: rec_type->class_type
1900 else
1901 vthis_value = d_null_pointer;
1902 } else {
1903 assert(0);
1908 if (vthis_value) {
1909 new_call = save_expr( new_call );
1910 setup_exp = irs->maybeCompound(setup_exp,
1911 build(MODIFY_EXPR, TREE_TYPE(vthis_field),
1912 irs->component( irs->indirect(new_call, rec_type),
1913 vthis_field ),
1914 vthis_value));
1918 new_call = irs->maybeCompound(setup_exp, new_call);
1920 // Constructor call
1921 if (member) {
1922 result = irs->call(member, new_call, arguments);
1923 } else {
1924 result = new_call;
1926 return irs->convertTo(result, base_type, type);
1928 case Tarray:
1930 assert( ! allocator );
1931 assert( arguments && arguments->dim > 0 );
1933 LibCall lib_call;
1935 Type * elem_init_type = newtype;
1937 /* First, skip past dynamic array dimensions/types that will be
1938 allocated by this call. */
1939 for (unsigned i = 0; i < arguments->dim; i++)
1940 elem_init_type = elem_init_type->toBasetype()->nextOf(); // assert ty == Tarray
1942 #if ! V2
1943 gcc_assert(! elem_init_type->isbit());
1944 #endif
1946 if (arguments->dim == 1)
1948 lib_call = elem_init_type->isZeroInit() ?
1949 LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
1951 tree args[2];
1952 args[0] = irs->typeinfoReference(type);
1953 args[1] = ((Expression *) arguments->data[0])->toElem(irs);
1954 result = irs->libCall(lib_call, 2, args, type->toCtype());
1956 else
1958 lib_call = elem_init_type->isZeroInit() ?
1959 LIBCALL_NEWARRAYMTP : LIBCALL_NEWARRAYMITP;
1961 tree dims_var = irs->exprVar(irs->arrayType(size_type_node, arguments->dim));
1963 tree dims_init;
1964 CtorEltMaker elms;
1966 elms.reserve( arguments->dim );
1967 for (unsigned i = 0; i < arguments->dim/* - 1*/; i++)
1968 elms.cons( irs->integerConstant(i, size_type_node),
1969 ((Expression*) arguments->data[i])->toElem(irs) );
1970 //elms.cons(final_length);
1971 dims_init = make_node(CONSTRUCTOR);
1972 TREE_TYPE( dims_init ) = TREE_TYPE( dims_var);
1973 CONSTRUCTOR_ELTS( dims_init ) = elms.head;
1974 DECL_INITIAL(dims_var) = dims_init;
1977 tree args[3];
1978 args[0] = irs->typeinfoReference(type);
1979 args[1] = irs->integerConstant(arguments->dim, Type::tint32); // The ndims arg is declared as 'int'
1980 args[2] = irs->addressOf(dims_var);
1982 result = irs->libCall(lib_call, 3, args, type->toCtype());
1983 result = irs->binding(dims_var, result);
1986 return irs->convertTo(result, base_type, type);
1988 break;
1989 default:
1991 Type * object_type = newtype;
1992 Type * handle_type = base_type->pointerTo();
1993 tree new_call;
1994 tree t;
1995 bool need_init = true;
1997 if (onstack) {
1998 tree stack_var = irs->localVar( object_type );
1999 irs->expandDecl(stack_var);
2000 new_call = irs->addressOf( stack_var );
2001 } else if (allocator) {
2002 new_call = irs->call(allocator, newargs);
2003 } else {
2004 tree args[2];
2005 LibCall lib_call = object_type->isZeroInit() ?
2006 LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
2007 args[0] = irs->typeinfoReference( object_type->arrayOf() );
2008 args[1] = irs->integerConstant(1, Type::tsize_t);
2009 new_call = irs->libCall(lib_call, 2, args);
2010 new_call = irs->darrayPtrRef(new_call);
2011 need_init = false;
2013 new_call = irs->nop(new_call, handle_type->toCtype());
2014 if ( need_init ) {
2015 // Save the result allocation call.
2016 new_call = save_expr( new_call );
2017 t = irs->indirect(new_call);
2018 t = build(MODIFY_EXPR, TREE_TYPE(t), t,
2019 irs->convertForAssignment(object_type->defaultInit(), object_type) );
2020 new_call = irs->compound(t, new_call);
2022 return irs->nop(new_call, type->toCtype());
2024 break;
2028 elem * ScopeExp::toElem(IRState* irs) {
2029 ::error("%s is not an expression", toChars());
2030 return irs->errorMark(type);
2033 elem * TypeExp::toElem(IRState* irs) {
2034 ::error("%s is not an expression", toChars());
2035 return irs->errorMark(type);
2038 elem * TypeDotIdExp::toElem(IRState* irs) {
2039 ::error("TypeDotIdExp::toElem: don't know what to do (%s)", toChars());
2040 return irs->errorMark(type);
2043 elem *
2044 StringExp::toElem(IRState * irs)
2046 Type * base_type = type->toBasetype();
2047 TY base_ty = type ? base_type->ty : (TY) Tvoid;
2048 tree value;
2050 switch (base_ty) {
2051 case Tarray:
2052 case Tpointer:
2053 // Assuming this->string is null terminated
2054 // .. need to terminate with more nulls for wchar and dchar?
2055 value = build_string((len + 1) * sz,
2056 gen.hostToTargetString((char *) string, len + 1, sz));
2057 break;
2058 case Tsarray:
2059 case Tvoid:
2060 value = build_string(len * sz,
2061 gen.hostToTargetString((char *) string, len, sz));
2062 break;
2063 default:
2064 error("Invalid type for string constant: %s", type->toChars());
2065 return irs->errorMark(type);
2068 // %% endianess of wchar and dchar
2069 TREE_CONSTANT (value) = 1;
2070 TREE_READONLY (value) = 1;
2071 // %% array type doesn't match string length if null term'd...
2072 TREE_TYPE( value ) = irs->arrayType(base_ty != Tvoid ?
2073 base_type->nextOf() : Type::tchar, len);
2075 switch (base_ty) {
2076 case Tarray:
2077 value = irs->darrayVal(type, len, irs->addressOf( value ));
2078 break;
2079 case Tpointer:
2080 value = irs->addressOf( value );
2081 break;
2082 case Tsarray:
2083 // %% needed?
2084 TREE_TYPE(value) = type->toCtype();
2085 break;
2086 default:
2087 // nothing
2088 break;
2090 return value;
2093 elem *
2094 TupleExp::toElem(IRState * irs)
2096 tree result = NULL_TREE;
2097 if (exps && exps->dim) {
2098 for (unsigned i = 0; i < exps->dim; ++i) {
2099 Expression * e = (Expression *) exps->data[i];
2100 result = irs->maybeVoidCompound(result, e->toElem(irs));
2102 } else
2103 result = d_void_zero_node;
2105 return result;
2108 /* Returns an expression that assignes the expressions in ALE to static
2109 array pointed to by MEM. */
2111 // probably will need to pass the D array element type to get assignmets correct...
2112 // [ [1,2,3], 4 ]; // doesn't work, so maybe not..
2113 // opt: if all/most constant, should make a var and do array copy
2114 tree
2115 array_literal_assign(IRState * irs, tree mem, ArrayLiteralExp * ale)
2117 tree result = NULL_TREE;
2118 tree offset = size_int(0);
2119 tree elem_size = size_int( ale->type->toBasetype()->nextOf()->size() );
2121 for (unsigned i = 0; i < ale->elements->dim; i++) {
2122 Expression * e = (Expression *) ale->elements->data[i];
2123 tree elemp_e = build2(PLUS_EXPR, TREE_TYPE(mem), mem, offset);
2124 tree assgn_e = irs->vmodify( irs->indirect(elemp_e),
2125 e->toElem(irs));
2126 result = irs->maybeCompound(result, assgn_e);
2128 offset = size_binop(PLUS_EXPR, offset, elem_size);
2130 return result;
2133 elem *
2134 ArrayLiteralExp::toElem(IRState * irs)
2136 Type * array_type = type->toBasetype();
2137 assert( array_type->ty == Tarray || array_type->ty == Tsarray ||
2138 array_type->ty == Tpointer );
2139 tree elem_type = array_type->nextOf()->toCtype();
2140 tree d_array_type = array_type->nextOf()->arrayOf()->toCtype();
2142 tree args[2] = { irs->typeinfoReference(array_type->nextOf()->arrayOf()),
2143 irs->integerConstant(elements->dim, size_type_node) };
2144 // Unfortunately, this does a useles initialization
2145 LibCall lib_call = array_type->nextOf()->isZeroInit() ?
2146 LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
2147 tree d_array = irs->libCall(lib_call, 2, args, d_array_type);
2149 tree mem = irs->maybeMakeTemp( irs->darrayPtrRef( d_array ));
2150 tree result = irs->maybeCompound( array_literal_assign(irs, mem, this),
2151 mem );
2152 if ( array_type->ty == Tarray ) {
2153 result = irs->darrayVal(d_array_type, elements->dim, result);
2154 } else {
2155 tree s_array_type = irs->arrayType(elem_type, elements->dim);
2156 if (array_type->ty == Tsarray)
2157 result = irs->indirect(result, s_array_type);
2160 return result;
2163 elem *
2164 AssocArrayLiteralExp::toElem(IRState * irs)
2166 TypeAArray * aa_type = (TypeAArray *)type->toBasetype();
2167 assert(aa_type->ty == Taarray);
2168 assert(keys != NULL);
2169 assert(values != NULL);
2171 tree keys_var = irs->exprVar(irs->arrayType(aa_type->index, keys->dim)); //?
2172 tree vals_var = irs->exprVar(irs->arrayType(aa_type->next, keys->dim));
2173 tree keys_ptr = irs->nop(irs->addressOf(keys_var),
2174 aa_type->index->pointerTo()->toCtype());
2175 tree vals_ptr = irs->nop(irs->addressOf(vals_var),
2176 aa_type->next->pointerTo()->toCtype());
2177 tree keys_offset = size_int(0);
2178 tree vals_offset = size_int(0);
2179 tree keys_size = size_int( aa_type->index->size() );
2180 tree vals_size = size_int( aa_type->next->size() );
2181 tree result = NULL_TREE;
2183 for (unsigned i = 0; i < keys->dim; i++)
2185 Expression * e;
2186 tree elemp_e, assgn_e;
2188 e = (Expression *) keys->data[i];
2189 elemp_e = build2(PLUS_EXPR, TREE_TYPE(keys_ptr), keys_ptr, keys_offset);
2190 assgn_e = irs->vmodify( irs->indirect(elemp_e), e->toElem(irs) );
2191 keys_offset = size_binop(PLUS_EXPR, keys_offset, keys_size);
2192 result = irs->maybeCompound(result, assgn_e);
2194 e = (Expression *) values->data[i];
2195 elemp_e = build2(PLUS_EXPR, TREE_TYPE(vals_ptr), vals_ptr, vals_offset);
2196 assgn_e = irs->vmodify( irs->indirect(elemp_e), e->toElem(irs) );
2197 vals_offset = size_binop(PLUS_EXPR, vals_offset, vals_size);
2198 result = irs->maybeCompound(result, assgn_e);
2201 tree args[4] = { irs->typeinfoReference(aa_type),
2202 irs->integerConstant(keys->dim, Type::tsize_t),
2203 keys_ptr, vals_ptr };
2204 result = irs->maybeCompound(result,
2205 irs->libCall(LIBCALL_ASSOCARRAYLITERALTP, 4, args));
2207 result = irs->binding(keys_var, irs->binding(vals_var, result));
2209 tree ctor = make_node( CONSTRUCTOR );
2210 CtorEltMaker ce;
2211 TREE_TYPE( ctor ) = aa_type->toCtype();
2212 ce.cons(TYPE_FIELDS(TREE_TYPE( ctor )), result);
2213 CONSTRUCTOR_ELTS( ctor ) = ce.head;
2215 return irs->nop(ctor, type->toCtype());
2218 elem *
2219 StructLiteralExp::toElem(IRState *irs)
2221 assert(irs->typesSame(type->toBasetype(), sd->type->toBasetype()));
2223 tree ctor = make_node( CONSTRUCTOR );
2224 CtorEltMaker ce;
2225 TREE_TYPE( ctor ) = type->toCtype();
2227 if (elements)
2228 for (unsigned i = 0; i < elements->dim; ++i)
2230 Expression * e = (Expression *) elements->data[i];
2231 if (e)
2233 VarDeclaration * fld = (VarDeclaration *) sd->fields.data[i];
2234 ce.cons(fld->csym->Stree, irs->convertTo(e, fld->type));
2238 CONSTRUCTOR_ELTS( ctor ) = ce.head;
2239 return ctor;
2242 elem *
2243 NullExp::toElem(IRState * irs)
2245 TY base_ty = type->toBasetype()->ty;
2246 // 0 -> dynamic array. This is a special case conversion.
2247 // Move to convert for convertTo if it shows up elsewhere.
2248 switch (base_ty) {
2249 case Tarray:
2250 return irs->darrayVal( type, 0, NULL );
2251 case Taarray:
2253 tree ctor = make_node(CONSTRUCTOR);
2254 tree fa;
2255 CtorEltMaker ce;
2257 TREE_TYPE(ctor) = type->toCtype();
2258 fa = TYPE_FIELDS(TREE_TYPE(ctor));
2259 ce.cons(fa, convert(TREE_TYPE(fa), integer_zero_node));
2260 CONSTRUCTOR_ELTS(ctor) = ce.head;
2261 return ctor;
2263 break;
2264 case Tdelegate:
2265 // makeDelegateExpression ?
2266 return irs->delegateVal(convert(ptr_type_node, integer_zero_node),
2267 convert(ptr_type_node, integer_zero_node), type);
2268 default:
2269 return convert( type->toCtype(), integer_zero_node );
2273 elem *
2274 ThisExp::toElem(IRState * irs) {
2275 if (var)
2276 return irs->var(var->isVarDeclaration());
2277 // %% DMD issue -- creates ThisExp without setting var to vthis
2278 // %%TODO: updated in 0.79-0.81?
2279 assert( irs->func );
2280 assert( irs->func->vthis );
2281 return irs->var(irs->func->vthis);
2284 elem *
2285 ComplexExp::toElem(IRState * irs)
2287 TypeBasic * compon_type;
2288 switch (type->toBasetype()->ty) {
2289 case Tcomplex32: compon_type = (TypeBasic *) Type::tfloat32; break;
2290 case Tcomplex64: compon_type = (TypeBasic *) Type::tfloat64; break;
2291 case Tcomplex80: compon_type = (TypeBasic *) Type::tfloat80; break;
2292 default:
2293 abort();
2295 return build_complex(type->toCtype(),
2296 irs->floatConstant(creall(value), compon_type),
2297 irs->floatConstant(cimagl(value), compon_type));
2300 elem *
2301 RealExp::toElem(IRState * irs)
2303 return irs->floatConstant(value, type->toBasetype()->isTypeBasic());
2306 elem *
2307 IntegerExp::toElem(IRState * irs)
2309 return irs->integerConstant(value, type);
2312 #if D_GCC_VER >= 40
2314 static void
2315 genericize_function(tree fndecl)
2317 FILE *dump_file;
2318 int local_dump_flags;
2319 #if 0
2320 struct cgraph_node *cgn;
2321 #endif
2323 /* Dump the C-specific tree IR. */
2324 dump_file = dump_begin (TDI_original, &local_dump_flags);
2325 if (dump_file)
2327 fprintf (dump_file, "\n;; Function %s",
2328 lang_hooks.decl_printable_name (fndecl, 2));
2329 fprintf (dump_file, " (%s)\n",
2330 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)));
2331 fprintf (dump_file, ";; enabled by -%s\n", dump_flag_name (TDI_original));
2332 fprintf (dump_file, "\n");
2334 //if (local_dump_flags & TDF_RAW)
2335 dump_node (DECL_SAVED_TREE (fndecl),
2336 TDF_SLIM | local_dump_flags, dump_file);
2337 //else
2338 //print_c_tree (dump_file, DECL_SAVED_TREE (fndecl));
2339 fprintf (dump_file, "\n");
2341 dump_end (TDI_original, dump_file);
2344 /* Go ahead and gimplify for now. */
2345 //push_context ();
2346 gimplify_function_tree (fndecl);
2347 //pop_context ();
2349 /* Dump the genericized tree IR. */
2350 dump_function (TDI_generic, fndecl);
2351 #if 0
2352 /* Genericize all nested functions now. We do things in this order so
2353 that items like VLA sizes are expanded properly in the context of
2354 the correct function. */
2355 cgn = cgraph_node (fndecl);
2356 for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
2357 genericize_function (cgn->decl);
2358 #endif
2361 #endif
2363 void
2364 FuncDeclaration::toObjFile(int multiobj)
2366 if (!g.ofile->shouldEmit(this))
2367 return;
2368 if (! global.params.useUnitTests && isUnitTestDeclaration())
2369 return;
2371 Symbol * this_sym = toSymbol();
2372 if (this_sym->outputStage)
2373 return;
2375 if (g.irs->shouldDeferFunction(this))
2376 return;
2378 this_sym->outputStage = InProgress;
2380 tree fn_decl = this_sym->Stree;
2382 if (! fbody) {
2383 if (! isNested()) {
2384 // %% Should set this earlier...
2385 DECL_EXTERNAL (fn_decl) = 1;
2386 TREE_PUBLIC( fn_decl ) = 1;
2388 g.ofile->rodc(fn_decl, 1);
2389 return;
2392 tree param_list;
2393 tree result_decl;
2394 tree parm_decl = NULL_TREE;
2395 tree block;
2396 #if D_NO_TRAMPOLINES
2397 tree static_chain_expr = NULL_TREE;
2398 #if V2
2399 FuncDeclaration * closure_func = NULL;
2400 tree closure_expr = NULL_TREE;
2401 #endif
2402 #endif
2403 ClassDeclaration * cd;
2404 AggregateDeclaration * ad = NULL;
2406 announce_function( fn_decl );
2407 IRState * irs = IRState::startFunction(this);
2408 #if V2
2409 irs->useClosure(NULL, NULL_TREE);
2410 #endif
2412 #if D_GCC_VER < 40
2413 bool saved_omit_frame_pointer = flag_omit_frame_pointer;
2414 flag_omit_frame_pointer = gen.originalOmitFramePointer || naked;
2416 if (gen.functionNeedsChain(this))
2417 push_function_context();
2418 #else
2419 // in 4.0, doesn't use push_function_context
2420 tree old_current_function_decl = current_function_decl;
2421 function * old_cfun = cfun;
2422 #endif
2424 current_function_decl = fn_decl;
2426 TREE_STATIC( fn_decl ) = 1;
2429 Type * func_type = tintro ? tintro : type;
2430 Type * ret_type = func_type->nextOf()->toBasetype();
2431 if (isMain() && ret_type->ty == Tvoid)
2432 ret_type = Type::tint32;
2433 result_decl = build_decl( RESULT_DECL, NULL_TREE, ret_type->toCtype() );
2435 g.ofile->setDeclLoc(result_decl, this);
2436 DECL_RESULT( fn_decl ) = result_decl;
2437 DECL_CONTEXT( result_decl ) = fn_decl;
2438 //layout_decl( result_decl, 0 );
2440 #if D_GCC_VER >= 40
2441 allocate_struct_function( fn_decl );
2442 // assuming the above sets cfun
2443 if (endloc.filename) {
2444 cfun->function_end_locus.file = endloc.filename;
2445 cfun->function_end_locus.line = endloc.linnum;
2446 } else {
2447 cfun->function_end_locus.file = DECL_SOURCE_FILE (fn_decl);
2448 cfun->function_end_locus.line = DECL_SOURCE_LINE (fn_decl);
2450 #endif
2452 param_list = NULL_TREE;
2454 #if V2
2455 bool needs_static_chain = irs->functionNeedsChain(this);
2456 #endif
2458 int n_parameters = parameters ? parameters->dim : 0;
2460 // Special arguments...
2461 static const int VTHIS = -2;
2462 static const int VARGUMENTS = -1;
2464 for (int i = VTHIS; i < (int) n_parameters; i++) {
2465 VarDeclaration * param = 0;
2466 tree parm_type = 0;
2468 parm_decl = 0;
2470 if (i == VTHIS) {
2471 if ( (ad = isThis()) )
2472 param = vthis;
2473 else if (isNested()) {
2474 /* DMD still generates a vthis, but it should not be
2475 referenced in any expression.
2477 This parameter is hidden from the debugger.
2479 parm_type = ptr_type_node;
2480 parm_decl = build_decl(PARM_DECL, NULL_TREE, parm_type);
2481 DECL_ARTIFICIAL( parm_decl ) = 1;
2482 DECL_IGNORED_P( parm_decl ) = 1;
2483 DECL_ARG_TYPE (parm_decl) = TREE_TYPE (parm_decl); // %% doc need this arg silently disappears
2484 #if D_NO_TRAMPOLINES
2485 #if V2
2486 if (! needs_static_chain)
2488 closure_func = toParent2()->isFuncDeclaration();
2489 closure_expr = parm_decl;
2491 else
2492 #endif
2494 static_chain_expr = parm_decl;
2496 #endif
2497 } else
2498 continue;
2499 } else if (i == VARGUMENTS) {
2500 if (v_arguments /*varargs && linkage == LINKd*/)
2501 param = v_arguments;
2502 else
2503 continue;
2504 } else {
2505 param = (VarDeclaration *) parameters->data[i];
2507 if (param) {
2508 parm_decl = param->toSymbol()->Stree;
2511 DECL_CONTEXT (parm_decl) = fn_decl;
2512 // param->loc is not set, so use the function's loc
2513 // %%doc not setting this crashes debug generating code
2514 g.ofile->setDeclLoc( parm_decl, param ? (Dsymbol*) param : (Dsymbol*) this );
2516 // chain them in the correct order
2517 param_list = chainon (param_list, parm_decl);
2520 // param_list is a number of PARM_DECL trees chained together (*not* a TREE_LIST of PARM_DECLs).
2521 // The leftmost parameter is the first in the chain. %% varargs?
2522 DECL_ARGUMENTS( fn_decl ) = param_list; // %% in treelang, useless ? because it just sets them to getdecls() later
2524 #if D_GCC_VER < 40
2525 rest_of_decl_compilation(fn_decl, NULL, /*toplevel*/1, /*atend*/0); // http://www.tldp.org/HOWTO/GCC-Frontend-HOWTO-7.html
2526 make_decl_rtl (fn_decl, NULL); // %% needed?
2527 #else
2528 rest_of_decl_compilation(fn_decl, /*toplevel*/1, /*atend*/0);
2529 #endif
2530 // ... has this here, but with more args...
2532 DECL_INITIAL( fn_decl ) = error_mark_node; // Just doing what they tell me to do...
2534 IRState::initFunctionStart(fn_decl, loc);
2535 #if D_NO_TRAMPOLINES
2536 /* If this is a member function that nested (possibly indirectly) in another
2537 function, construct an expession for this member function's static chain
2538 by going through parent link of nested classes.
2540 if (ad && (cd = ad->isClassDeclaration()) && ! (static_chain_expr
2541 #if V2
2542 || closure_expr
2543 #endif
2544 )) {
2545 /* D 2.0 Closures: this->vthis is passed as a normal parameter and
2546 is valid to access as Stree before the closure frame is created. */
2547 tree t = vthis->toSymbol()->Stree;
2548 while ( cd->isNested() ) {
2549 Dsymbol * d = cd->toParent2();
2552 tree vthis_field = cd->vthis->toSymbol()->Stree;
2553 t = irs->component(irs->indirect(t), vthis_field);
2554 FuncDeclaration * f;
2555 if ( (f = d->isFuncDeclaration() )) {
2556 #if V2
2557 if (! needs_static_chain)
2559 closure_expr = t;
2560 closure_func = f;
2562 else
2563 #endif
2565 static_chain_expr = t;
2567 break;
2568 } else if ( (cd = d->isClassDeclaration()) ) {
2569 // nothing
2570 } else {
2571 assert(0);
2575 #endif
2577 #if D_GCC_VER >= 40
2578 cfun->naked = naked ? 1 : 0;
2579 #endif
2580 #if D_GCC_VER < 40
2581 // Must be done before expand_function_start.
2582 cfun->static_chain_expr = static_chain_expr;
2584 expand_function_start (fn_decl, 0);
2586 /* If this function is the C `main', emit a call to `__main'
2587 to run global initializers, etc. */
2588 if (linkage == LINKc &&
2589 DECL_ASSEMBLER_NAME (fn_decl)
2590 && MAIN_NAME_P (DECL_ASSEMBLER_NAME (fn_decl)) // other langs use DECL_NAME..
2591 && DECL_FILE_SCOPE_P (fn_decl)
2593 expand_main_function ();
2596 //cfun->x_whole_function_mode_p = 1; // %% I gues...
2597 //cfun->function_frequency = ; // %% it'd be nice to do something with this..
2598 //need DECL_RESULT ?
2600 // Start a binding level for the function/arguments
2601 (*lang_hooks.decls.pushlevel) (0);
2602 expand_start_bindings (2);
2604 // Add the argument declarations to the symbol table for the back end
2605 set_decl_binding_chain( DECL_ARGUMENTS( fn_decl ));
2607 // %% TREE_ADDRESSABLE and TREE_USED...
2609 // Start a binding level for the function body
2610 //(*lang_hooks.decls.pushlevel) (0);
2611 #else
2612 pushlevel(0);
2613 irs->pushStatementList();
2614 #endif
2616 irs->startScope();
2617 irs->doLineNote(loc);
2619 #if D_GCC_VER >= 40
2620 if (static_chain_expr) {
2621 cfun->custom_static_chain = 1;
2622 irs->doExp( build2(MODIFY_EXPR, ptr_type_node,
2623 build0( STATIC_CHAIN_DECL, ptr_type_node ), static_chain_expr) );
2625 #endif
2627 #if V2
2628 if (static_chain_expr || closure_expr)
2629 irs->useParentClosure();
2631 if (closure_expr)
2633 if (! DECL_P(closure_expr)) {
2634 tree c = irs->localVar(ptr_type_node);
2635 DECL_INITIAL(c) = closure_expr;
2636 irs->expandDecl(c);
2637 closure_expr = c;
2639 irs->useClosure(closure_func, closure_expr);
2642 buildClosure(irs); // may change irs->closureLink and irs->closureFunc
2643 #endif
2645 if (vresult)
2646 irs->emitLocalVar(vresult);
2648 if (v_argptr) {
2649 #if D_GCC_VER < 40
2650 tree var = irs->var(v_argptr);
2651 tree init_exp = irs->buildCall(void_type_node,
2652 irs->addressOf( built_in_decls[BUILT_IN_VA_START] ),
2653 tree_cons(NULL_TREE, irs->addressOf(var),
2654 tree_cons( NULL_TREE, parm_decl, NULL_TREE)));
2655 tree cleanup = irs->buildCall(void_type_node,
2656 irs->addressOf( built_in_decls[BUILT_IN_VA_END] ),
2657 tree_cons(NULL_TREE, irs->addressOf(var), NULL_TREE));
2658 v_argptr->init = NULL; // VoidInitializer?
2659 irs->emitLocalVar(v_argptr, true);
2661 #if V2
2662 /* Note: cleanup will not run if v_argptr is a closure variable.
2663 Probably okay for now because va_end doesn't do anything for any
2664 GCC 3.3.x target.
2666 if (! v_argptr->toSymbol()->SclosureField)
2667 #endif
2669 expand_decl_cleanup(var, cleanup);
2670 expand_expr_stmt_value(init_exp, 0, 1);
2672 #else
2673 irs->pushStatementList();
2674 #endif
2676 if (v_arguments_var)
2677 irs->emitLocalVar(v_arguments_var, true);
2679 Statement * the_body = fbody;
2680 if (isSynchronized()) {
2681 AggregateDeclaration * asym;
2682 ClassDeclaration * sym;
2684 if ( (asym = isMember()) && (sym = asym->isClassDeclaration()) ) {
2685 if (vthis != NULL) {
2686 VarExp * ve = new VarExp(fbody->loc, vthis);
2687 the_body = new SynchronizedStatement(fbody->loc, ve, fbody);
2688 } else {
2689 if (!sym->vclassinfo)
2690 sym->vclassinfo = new ClassInfoDeclaration(sym);
2691 Expression * e = new VarExp(fbody->loc, sym->vclassinfo);
2692 e = new AddrExp(fbody->loc, e);
2693 e->type = sym->type;
2694 the_body = new SynchronizedStatement(fbody->loc, e, fbody);
2696 } else {
2697 error("synchronized function %s must be a member of a class", toChars());
2700 the_body->toIR(irs);
2702 if (this_sym->otherNestedFuncs)
2704 for (unsigned i = 0; i < this_sym->otherNestedFuncs->dim; ++i)
2706 ((FuncDeclaration *) this_sym->otherNestedFuncs->data[i])->toObjFile(false);
2710 #ifdef TARGET_80387
2711 /* Users of inline assembler statements expect to be able to leave
2712 the result in ST(0). Because GCC does not know about this, it
2713 will load NaN before generating the return instruction.
2715 Solve this by faking an instruction that we claim loads a value
2716 into ST(0), make GCC store it into a temp variable, and then
2717 return the temp variable.
2719 When optimization is turned on, this whole process results in
2720 no extra code!
2722 /* This would apply to complex types as well, but GDC currently
2723 returns complex types as a struct instead of in ST(0) and ST(1).
2725 if (inlineAsm && ! naked && type->nextOf()->isfloating() &&
2726 ! type->nextOf()->iscomplex())
2728 tree result_var = irs->localVar(TREE_TYPE(result_decl));
2730 tree nop_str = build_string(0, "");
2731 tree cns_str = build_string(2, "=t");
2732 tree out_arg = tree_cons(tree_cons(NULL_TREE, cns_str, NULL_TREE),
2733 result_var, NULL_TREE);
2735 irs->expandDecl(result_var);
2736 irs->doAsm(nop_str, out_arg, NULL_TREE, NULL_TREE);
2737 irs->doReturn( build(MODIFY_EXPR, TREE_TYPE(result_decl),
2738 result_decl, result_var) );
2740 #endif
2743 #if D_GCC_VER >= 40
2744 if (v_argptr) {
2745 tree body = irs->popStatementList();
2746 tree var = irs->var(v_argptr);
2747 tree init_exp = irs->buildCall(void_type_node,
2748 irs->addressOf( built_in_decls[BUILT_IN_VA_START] ),
2749 tree_cons(NULL_TREE, irs->addressOf(var),
2750 tree_cons( NULL_TREE, parm_decl, NULL_TREE)));
2751 v_argptr->init = NULL; // VoidInitializer?
2752 irs->emitLocalVar(v_argptr, true);
2753 irs->addExp(init_exp);
2755 tree cleanup = irs->buildCall(void_type_node,
2756 irs->addressOf( built_in_decls[BUILT_IN_VA_END] ),
2757 tree_cons(NULL_TREE, irs->addressOf(var), NULL_TREE));
2758 irs->addExp( build2( TRY_FINALLY_EXPR, void_type_node, body, cleanup ));
2760 #endif
2762 irs->endScope();
2764 #if D_GCC_VER < 40
2765 expand_function_end ();
2766 block = (*lang_hooks.decls.poplevel) (1, 0, 1);
2767 #else
2768 DECL_SAVED_TREE(fn_decl) = irs->popStatementList();
2770 /* In tree-nested.c, init_tmp_var expects a statement list to come
2771 from somewhere. popStatementList returns expressions when
2772 there is a single statement. This code creates a statemnt list
2773 unconditionally because the DECL_SAVED_TREE will always be a
2774 BIND_EXPR. */
2776 if (1)
2778 tree body = DECL_SAVED_TREE(fn_decl);
2779 tree t;
2781 gcc_assert(TREE_CODE(body) == BIND_EXPR);
2783 t = TREE_OPERAND(body, 1);
2784 if (TREE_CODE(t) != STATEMENT_LIST) {
2785 tree sl = alloc_stmt_list();
2786 append_to_statement_list_force(t, & sl);
2787 TREE_OPERAND(body, 1) = sl;
2788 } else if (! STATEMENT_LIST_HEAD(t)) {
2789 /* For empty functions: Without this, there is a
2790 segfault when inlined. Seen on build=ppc-linux but
2791 not others (why?). */
2792 append_to_statement_list_force(
2793 build1(RETURN_EXPR,void_type_node,NULL_TREE), & t);
2797 //block = (*lang_hooks.decls.poplevel) (1, 0, 1);
2798 block = poplevel(1, 0, 1);
2799 #endif
2801 DECL_INITIAL (fn_decl) = block; // %% redundant, see poplevel
2802 BLOCK_SUPERCONTEXT( DECL_INITIAL (fn_decl) ) = fn_decl; // done in C, don't know effect
2804 #if D_GCC_VER < 40
2805 expand_end_bindings (NULL_TREE, 0, 1);
2806 #else
2807 if (! errorcount && ! global.errors)
2808 genericize_function (fn_decl);
2809 #endif
2811 this_sym->outputStage = Finished;
2812 if (! errorcount && ! global.errors)
2813 g.ofile->outputFunction(this);
2815 #if D_GCC_VER < 40
2816 //rest_of_compilation( fn_decl );
2817 if (gen.functionNeedsChain(this))
2818 pop_function_context();
2819 else
2820 current_function_decl = NULL_TREE; // must come before endFunction
2822 g.irs->endFunction();
2824 flag_omit_frame_pointer = saved_omit_frame_pointer;
2825 #else
2826 current_function_decl = old_current_function_decl; // must come before endFunction
2827 cfun = old_cfun;
2829 irs->endFunction();
2830 #endif
2833 #if V2
2835 void
2836 FuncDeclaration::buildClosure(IRState * irs)
2838 FuncFrameInfo * ffi = irs->getFrameInfo(this);
2839 if (! ffi->creates_closure)
2840 return;
2842 tree closure_rec_type = make_node(RECORD_TYPE);
2843 tree ptr_field = build_decl(FIELD_DECL, get_identifier("__closptr"), ptr_type_node);
2844 DECL_CONTEXT(ptr_field) = closure_rec_type;
2845 ListMaker fields;
2846 fields.chain(ptr_field);
2848 for (unsigned i = 0; i < closureVars.dim; ++i)
2850 VarDeclaration *v = (VarDeclaration *)closureVars.data[i];
2851 tree field = build_decl(FIELD_DECL,
2852 v->ident ? get_identifier(v->ident->string) : NULL_TREE,
2853 gen.trueDeclarationType(v));
2854 v->toSymbol()->SclosureField = field;
2855 g.ofile->setDeclLoc( field, v );
2856 DECL_CONTEXT(field) = closure_rec_type;
2857 fields.chain(field);
2859 TYPE_FIELDS(closure_rec_type) = fields.head;
2860 layout_type(closure_rec_type);
2862 ffi->closure_rec = closure_rec_type;
2864 tree closure_ptr = irs->localVar(build_pointer_type(closure_rec_type));
2865 DECL_NAME(closure_ptr) = get_identifier("__closptr");
2866 DECL_ARTIFICIAL(closure_ptr) = DECL_IGNORED_P(closure_ptr) = 0;
2868 tree arg = d_convert_basic(Type::tsize_t->toCtype(),
2869 TYPE_SIZE_UNIT(closure_rec_type));
2871 DECL_INITIAL(closure_ptr) =
2872 irs->nop(irs->libCall(LIBCALL_ALLOCMEMORY, 1, & arg),
2873 TREE_TYPE(closure_ptr));
2874 irs->expandDecl(closure_ptr);
2876 // set the first entry to the parent closure, if any
2877 tree cl = irs->closureLink();
2878 if (cl)
2879 irs->doExp(irs->vmodify(irs->component(irs->indirect(closure_ptr),
2880 ptr_field), cl));
2882 // copy parameters that are referenced nonlocally
2883 for (unsigned i = 0; i < closureVars.dim; i++)
2885 VarDeclaration *v = (VarDeclaration *)closureVars.data[i];
2887 if (! v->isParameter())
2888 continue;
2890 Symbol * vsym = v->toSymbol();
2891 irs->doExp(irs->vmodify(irs->component(irs->indirect(closure_ptr),
2892 vsym->SclosureField), vsym->Stree));
2895 irs->useClosure(this, closure_ptr);
2898 #endif
2900 void
2901 Module::genobjfile(int multiobj)
2903 /* Normally would create an ObjFile here, but gcc is limited to one obj file
2904 per pass and there may be more than one module per obj file. */
2905 assert(g.ofile);
2907 g.ofile->beginModule(this);
2909 if (members) {
2910 for (unsigned i = 0; i < members->dim; i++) {
2911 Dsymbol * dsym = (Dsymbol *) members->data[i];
2913 dsym->toObjFile(multiobj);
2917 if (needModuleInfo()) {
2919 ModuleInfo & mi = * g.mi();
2921 if (mi.ctors.dim)
2922 sctor = g.ofile->doFunctionToCallFunctions("*__modctor", & mi.ctors)->toSymbol();
2923 if (mi.dtors.dim)
2924 sdtor = g.ofile->doFunctionToCallFunctions("*__moddtor", & mi.dtors)->toSymbol();
2925 if (mi.unitTests.dim)
2926 stest = g.ofile->doFunctionToCallFunctions("*__modtest", & mi.unitTests)->toSymbol();
2929 genmoduleinfo();
2932 g.ofile->endModule();
2935 // This is not used for GCC
2936 unsigned Type::totym() { return 0; }
2938 type *
2939 Type::toCtype() {
2940 if (! ctype) {
2941 switch (ty) {
2942 case Tvoid: return void_type_node;
2943 case Tint8: return intQI_type_node;
2944 case Tuns8: return unsigned_intQI_type_node;
2945 case Tint16: return intHI_type_node;
2946 case Tuns16: return unsigned_intHI_type_node;
2947 case Tint32: return intSI_type_node;
2948 case Tuns32: return unsigned_intSI_type_node;
2949 case Tint64: return intDI_type_node;
2950 case Tuns64: return unsigned_intDI_type_node;
2951 case Tfloat32: return float_type_node;
2952 case Tfloat64: return double_type_node;
2953 case Tfloat80: return long_double_type_node;
2954 case Tcomplex32: return complex_float_type_node;
2955 case Tcomplex64: return complex_double_type_node;
2956 case Tcomplex80: return complex_long_double_type_node;
2957 case Tbool:
2958 if (int_size_in_bytes( boolean_type_node ) == 1)
2959 return boolean_type_node;
2960 // else, drop through
2961 case Tbit:
2962 ctype = make_unsigned_type(1);
2963 TREE_SET_CODE(ctype, BOOLEAN_TYPE);
2964 assert(int_size_in_bytes( ctype ) == 1);
2965 dkeep(ctype);
2966 return ctype;
2967 case Tchar:
2968 ctype = build_type_copy( unsigned_intQI_type_node );
2969 return ctype;
2970 case Twchar:
2971 ctype = build_type_copy( unsigned_intHI_type_node );
2972 return ctype;
2973 case Tdchar:
2974 ctype = build_type_copy( unsigned_intSI_type_node );
2975 return ctype;
2976 case Timaginary32:
2977 ctype = build_type_copy( float_type_node );
2978 return ctype;
2979 case Timaginary64:
2980 ctype = build_type_copy( double_type_node );
2981 return ctype;
2982 case Timaginary80:
2983 ctype = build_type_copy( long_double_type_node );
2984 return ctype;
2986 case Terror: return error_mark_node;
2988 /* We can get Tident with forward references. There seems to
2989 be a legitame case (dstress:debug_info_03). I have not seen this
2990 happen for an error, so maybe it's okay...
2992 A way to handle this would be to partially construct
2993 function types and not complete it until it was actually
2994 used in a call. */
2995 case Tident: return void_type_node;
2997 default:
2998 ::error("unexpected call to Type::toCtype() for %s\n", this->toChars());
2999 abort();
3000 return NULL_TREE;
3003 return ctype;
3006 // This is not used for GCC
3007 type * Type::toCParamtype() { return 0; }
3008 // This is not used for GCC
3009 Symbol * Type::toSymbol() { return 0; }
3011 static void
3012 apply_type_attributes(Expressions * attrs, tree & type_node, bool in_place = false)
3014 if (attrs)
3015 decl_attributes(& type_node, gen.attributes(attrs),
3016 in_place ? ATTR_FLAG_TYPE_IN_PLACE : 0);
3019 type *
3020 TypeTypedef::toCtype()
3022 // %%TODO: create info for debugging
3023 tree type_node = sym->basetype->toCtype();
3024 apply_type_attributes(sym->attributes, type_node);
3025 return type_node;
3027 tree type_decl = build_decl(TYPE_DECL, get_identifier( sym->ident->string ),
3028 type_node);
3029 DECL_CONTEXT( type_decl ) =
3030 rest_of_decl_compilation(type_decl, NULL, ?context?, 0); //%% flag
3034 type *
3035 TypeTypedef::toCParamtype()
3037 return toCtype();
3040 void
3041 TypedefDeclaration::toDebug()
3046 type *
3047 TypeEnum::toCtype()
3049 if (! ctype) {
3050 tree enum_mem_type_node = sym->memtype->toCtype();
3052 ctype = make_node( ENUMERAL_TYPE );
3053 // %% c-decl.c: if (flag_short_enums) TYPE_PACKED(enumtype) = 1;
3054 TYPE_PRECISION( ctype ) = size(0) * 8;
3055 TYPE_SIZE( ctype ) = 0; // as in c-decl.c
3056 apply_type_attributes(sym->attributes, ctype, true);
3057 #if V2
3058 /* Because minval and maxval are of this type,
3059 ctype needs to be completed enough for
3060 build_int_cst to work properly. */
3061 TYPE_MIN_VALUE( ctype ) = sym->minval->toElem(& gen);
3062 TYPE_MAX_VALUE( ctype ) = sym->maxval->toElem(& gen);
3063 #else
3064 TYPE_MIN_VALUE( ctype ) = gen.integerConstant(sym->minval, enum_mem_type_node);
3065 TYPE_MAX_VALUE( ctype ) = gen.integerConstant(sym->maxval, enum_mem_type_node);
3066 #endif
3067 layout_type( ctype );
3068 TREE_UNSIGNED( ctype ) = isunsigned() != 0; // layout_type can change this
3070 // Move this to toDebug() ?
3071 ListMaker enum_values;
3072 if (sym->members) {
3073 for (unsigned i = 0; i < sym->members->dim; i++) {
3074 EnumMember * member = (EnumMember *) sym->members->data[i];
3075 char * ident;
3077 if (sym->ident)
3078 ident = concat(sym->ident->string, ".",
3079 member->ident->string, NULL);
3080 else
3081 ident = (char *) member->ident->string;
3083 enum_values.cons( get_identifier(ident),
3084 gen.integerConstant(member->value->toInteger(), ctype) );
3086 if (sym->ident)
3087 free(ident);
3090 TYPE_VALUES( ctype ) = enum_values.head;
3092 g.ofile->initTypeDecl(ctype, sym);
3093 g.ofile->declareType(ctype, sym);
3095 return ctype;
3098 type *
3099 TypeStruct::toCtype()
3101 if (! ctype) {
3102 // need to set this right away in case of self-references
3103 ctype = make_node( sym->isUnionDeclaration() ? UNION_TYPE : RECORD_TYPE );
3105 TYPE_LANG_SPECIFIC( ctype ) = build_d_type_lang_specific(this);
3107 /* %% copied from AggLayout::finish -- also have to set the size
3108 for (indirect) self-references. */
3110 /* Must set up the overall size, etc. before determining the
3111 context or laying out fields as those types may make references
3112 to this type. */
3113 TYPE_SIZE( ctype ) = bitsize_int( sym->structsize * BITS_PER_UNIT );
3114 TYPE_SIZE_UNIT( ctype ) = size_int( sym->structsize );
3115 TYPE_ALIGN( ctype ) = sym->alignsize * BITS_PER_UNIT; // %%doc int, not a tree
3116 // TYPE_ALIGN_UNIT is not an lvalue
3117 TYPE_PACKED ( ctype ) = TYPE_PACKED ( ctype ); // %% todo
3118 apply_type_attributes(sym->attributes, ctype, true);
3119 compute_record_mode ( ctype );
3121 // %% stor-layout.c:finalize_type_size ... it's private to that file
3123 TYPE_CONTEXT( ctype ) = gen.declContext(sym);
3125 g.ofile->initTypeDecl(ctype, sym);
3127 AggLayout agg_layout(sym, ctype);
3128 agg_layout.go();
3130 /* On PowerPC 64, GCC may not always clear the padding at the end
3131 of the struct. Adding 32-bit words at the end helps. */
3132 if (global.params.isX86_64 && ! sym->isUnionDeclaration() && sym->fields.dim)
3134 target_size_t ofs;
3136 VarDeclaration * last_decl = ((VarDeclaration*)(sym->fields.data[sym->fields.dim-1]));
3137 ofs = last_decl->offset + last_decl->size(0);
3139 while (ofs & 3)
3140 ++ofs;
3141 while (ofs < sym->structsize && sym->structsize - ofs >= 4)
3143 tree f = build_decl(FIELD_DECL, get_identifier("_pad"), d_type_for_size(32, 1));
3144 DECL_FCONTEXT( f ) = ctype;
3145 DECL_ARTIFICIAL( f ) = DECL_IGNORED_P( f ) = 1;
3146 DECL_IGNORED_P( f ) = 1;
3147 agg_layout.addField(f, ofs);
3148 ofs += 4;
3152 agg_layout.finish(sym->attributes);
3154 return ctype;
3157 void
3158 StructDeclaration::toDebug()
3160 tree ctype = type->toCtype();
3161 g.ofile->addAggMethods(ctype, this);
3162 g.ofile->declareType(ctype, this);
3165 Symbol * TypeClass::toSymbol() { return sym->toSymbol(); }
3167 unsigned TypeFunction::totym() { return 0; } // Unused
3169 type *
3170 TypeFunction::toCtype() {
3171 // %%TODO: If x86, and D linkage, use regparm(1)
3173 if (! ctype) {
3174 ListMaker type_list;
3175 tree ret_type;
3177 // Function type can be reference by parameters, etc. Set ctype early.
3178 ctype = make_node(FUNCTION_TYPE);
3180 if (varargs == 1 && linkage == LINKd) {
3181 // hidden _arguments parameter
3182 #if BREAKABI
3183 type_list.cons( Type::typeinfotypelist->type->toCtype() );
3184 #else
3185 type_list.cons( Type::typeinfo->type->arrayOf()->toCtype() );
3186 #endif
3189 if (parameters) {
3190 size_t n_args = Argument::dim(parameters);
3191 for (size_t i = 0; i < n_args; i++) {
3192 Argument * arg = Argument::getNth(parameters, i);
3193 type_list.cons( IRState::trueArgumentType(arg) );
3197 /* Last parm if void indicates fixed length list (as opposed to
3198 printf style va_* list). */
3199 if (varargs != 1)
3200 type_list.cons( void_type_node );
3202 if (next) {
3203 ret_type = next->toCtype();
3204 } else {
3205 ret_type = void_type_node;
3208 TREE_TYPE( ctype ) = ret_type;
3209 TYPE_ARG_TYPES( ctype ) = type_list.head;
3210 layout_type(ctype);
3212 if (linkage == LINKwindows)
3213 ctype = gen.addTypeAttribute(ctype, "stdcall");
3215 #ifdef D_DMD_CALLING_CONVENTIONS
3216 // W.I.P.
3217 /* Setting this on all targets. TARGET_RETURN_IN_MEMORY has precedence
3218 over this attribute. So, only targets on which flag_pcc_struct_return
3219 is considered will be affected. */
3220 if ( (linkage == LINKd && next->size() <= 8) ||
3221 (next && next->toBasetype()->ty == Tarray))
3222 ctype = gen.addTypeAttribute(ctype, "no_pcc_struct_return");
3224 #ifdef TARGET_386
3225 if (linkage == LINKd && ! TARGET_64BIT)
3226 ctype = gen.addTypeAttribute(ctype, "regparm", integer_one_node);
3227 #endif
3228 #endif
3229 dkeep(ctype);
3231 return ctype;
3234 enum RET
3235 TypeFunction::retStyle()
3237 /* Need the ctype to determine this, but this is called from
3238 the front end before semantic processing is finished. An
3239 accurate value is not currently needed anyway. */
3240 return RETstack;
3243 type *
3244 TypeSArray::toCtype()
3246 if (! ctype) {
3247 if (dim->isConst() && dim->type->isintegral()) {
3248 uinteger_t size = dim->toUInteger();
3250 #if ! V2
3251 gcc_assert(! next->isbit());
3252 #endif
3254 if (next->toBasetype()->ty == Tvoid)
3255 ctype = gen.arrayType(Type::tuns8, size);
3256 else
3257 ctype = gen.arrayType(next, size);
3259 } else {
3260 ::error("invalid expressions for static array dimension: %s", dim->toChars());
3261 abort();
3264 return ctype;
3267 type *TypeSArray::toCParamtype() { return 0; }
3269 type *
3270 TypeDArray::toCtype()
3272 if (! ctype)
3273 ctype = gen.twoFieldType(Type::tsize_t, next->pointerTo(), this,
3274 "length", "ptr");
3275 return ctype;
3278 type *
3279 TypeAArray::toCtype()
3281 /* Dependencies:
3283 IRState::convertForCondition
3284 more...
3288 if (! ctype)
3290 /* Library functions expect a struct-of-pointer which could be passed
3291 differently from a pointer. */
3292 static tree aa_type = NULL_TREE;
3293 if (! aa_type)
3295 aa_type = make_node( RECORD_TYPE );
3296 tree f0 = build_decl(FIELD_DECL, get_identifier("ptr"), ptr_type_node);
3297 DECL_CONTEXT(f0) = aa_type;
3298 TYPE_FIELDS(aa_type) = f0;
3299 layout_type(aa_type);
3301 dkeep(aa_type);
3303 ctype = aa_type;
3305 return ctype;
3308 type *
3309 TypePointer::toCtype()
3311 if (! ctype)
3312 ctype = build_pointer_type( next->toCtype() );
3313 return ctype;
3316 type *
3317 TypeDelegate::toCtype()
3319 if (! ctype) {
3320 assert(next->toBasetype()->ty == Tfunction);
3321 ctype = gen.twoFieldType(Type::tvoid->pointerTo(), next->pointerTo(),
3322 this, "object", "func");
3323 dkeep(ctype);
3325 return ctype;
3328 /* Create debug information for a ClassDeclaration's inheritance tree.
3329 Interfaces are not included. */
3330 static tree
3331 binfo_for(tree tgt_binfo, ClassDeclaration * cls)
3333 tree binfo =
3334 #if D_GCC_VER < 40
3335 make_tree_vec(BINFO_ELTS)
3336 #else
3337 make_tree_binfo(1)
3338 #endif
3340 TREE_TYPE (binfo) = TREE_TYPE( cls->type->toCtype() ); // RECORD_TYPE, not REFERENCE_TYPE
3341 BINFO_INHERITANCE_CHAIN(binfo) = tgt_binfo;
3342 BINFO_OFFSET (binfo) = size_zero_node; // %% type?, otherwize, integer_zero_node
3344 if (cls->baseClass) {
3345 #if D_GCC_VER < 40
3346 BINFO_BASETYPES(binfo) = make_tree_vec(1);
3347 BINFO_BASETYPE(binfo, 0) = binfo_for(binfo, cls->baseClass);
3348 #else
3349 BINFO_BASE_APPEND(binfo, binfo_for(binfo, cls->baseClass));
3350 #endif
3351 #ifdef BINFO_BASEACCESSES
3352 #if D_GCC_VER >= 40
3353 #error update vector stuff
3354 #endif
3355 tree prot_tree;
3357 BINFO_BASEACCESSES(binfo) = make_tree_vec(1);
3358 switch ( ((BaseClass *) cls->baseclasses.data[0])->protection ) {
3359 case PROTpublic:
3360 prot_tree = access_public_node;
3361 break;
3362 case PROTprotected:
3363 prot_tree = access_protected_node;
3364 break;
3365 case PROTprivate:
3366 prot_tree = access_private_node;
3367 break;
3368 default:
3369 prot_tree = access_public_node;
3370 break;
3372 BINFO_BASEACCESS(binfo,0) = prot_tree;
3373 #endif
3376 return binfo;
3379 /* Create debug information for an InterfaceDeclaration's inheritance
3380 tree. In order to access all inherited methods in the debugger,
3381 the entire tree must be described.
3383 This function makes assumptions about inherface layout. */
3384 static tree
3385 intfc_binfo_for(tree tgt_binfo, ClassDeclaration * iface, unsigned & inout_offset)
3387 tree binfo =
3388 #if D_GCC_VER < 40
3389 make_tree_vec(BINFO_ELTS)
3390 #else
3391 make_tree_binfo(iface->baseclasses.dim)
3392 #endif
3394 TREE_TYPE (binfo) = TREE_TYPE( iface->type->toCtype() ); // RECORD_TYPE, not REFERENCE_TYPE
3395 BINFO_INHERITANCE_CHAIN(binfo) = tgt_binfo;
3396 BINFO_OFFSET (binfo) = size_int(inout_offset * PTRSIZE);
3398 if (iface->baseclasses.dim) {
3399 #if D_GCC_VER < 40
3400 BINFO_BASETYPES(binfo) = make_tree_vec(iface->baseclasses.dim);
3401 #endif
3402 #ifdef BINFO_BASEACCESSES
3403 BINFO_BASEACCESSES(binfo) = make_tree_vec(iface->baseclasses.dim);
3404 #endif
3406 for (unsigned i = 0; i < iface->baseclasses.dim; i++) {
3407 BaseClass * bc = (BaseClass *) iface->baseclasses.data[i];
3409 if (i)
3410 inout_offset++;
3412 #if D_GCC_VER < 40
3413 BINFO_BASETYPE(binfo, i) = intfc_binfo_for(binfo, bc->base, inout_offset);
3414 #else
3415 BINFO_BASE_APPEND(binfo, intfc_binfo_for(binfo, bc->base, inout_offset));
3416 #endif
3417 #ifdef BINFO_BASEACCESSES
3418 tree prot_tree;
3419 switch ( bc->protection ) {
3420 case PROTpublic:
3421 prot_tree = access_public_node;
3422 break;
3423 case PROTprotected:
3424 prot_tree = access_protected_node;
3425 break;
3426 case PROTprivate:
3427 prot_tree = access_private_node;
3428 break;
3429 default:
3430 prot_tree = access_public_node;
3431 break;
3433 BINFO_BASEACCESS(binfo, i) = prot_tree;
3434 #endif
3437 return binfo;
3440 type *
3441 TypeClass::toCtype()
3443 if (! ctype) {
3444 tree rec_type;
3445 Array base_class_decls;
3446 bool inherited = sym->baseClass != 0;
3447 tree obj_rec_type;
3448 tree vfield;
3450 /* Need to set ctype right away in case of self-references to
3451 the type during this call. */
3452 rec_type = make_node( RECORD_TYPE );
3453 //apply_type_attributes(sym->attributes, rec_type, true);
3454 ctype = build_reference_type( rec_type );
3455 dkeep(ctype); // because BINFO moved out to toDebug
3456 g.ofile->initTypeDecl(rec_type, sym);
3458 obj_rec_type = TREE_TYPE( gen.getObjectType()->toCtype() );
3460 // Note that this is set on the reference type, not the record type.
3461 TYPE_LANG_SPECIFIC( ctype ) = build_d_type_lang_specific( this );
3463 AggLayout agg_layout(sym, rec_type);
3465 // Most of this silly code is just to produce correct debugging information.
3467 /* gdb apparently expects the vtable field to be named
3468 "_vptr$...." (stabsread.c) Otherwise, the debugger gives
3469 lots of annoying error messages. C++ appends the class
3470 name of the first base witht that field after the '$'. */
3471 /* update: annoying messages might not appear anymore after making
3472 other changes */
3473 // Add the virtual table pointer
3474 tree decl = build_decl(FIELD_DECL, get_identifier("_vptr$"), /*vtbl_type*/d_vtbl_ptr_type_node);
3475 agg_layout.addField( decl, 0 ); // %% target stuff..
3477 if (inherited) {
3478 vfield = copy_node( decl );
3479 DECL_ARTIFICIAL( decl ) = DECL_IGNORED_P( decl ) = 1;
3480 } else {
3481 vfield = decl;
3483 DECL_VIRTUAL_P( vfield ) = 1;
3484 TYPE_VFIELD( rec_type ) = vfield; // This only seems to affect debug info
3486 if (! sym->isInterfaceDeclaration()) {
3487 DECL_FCONTEXT( vfield ) = obj_rec_type;
3489 // Add the monitor
3490 // %% target type
3491 decl = build_decl(FIELD_DECL, get_identifier("_monitor"), ptr_type_node);
3492 DECL_FCONTEXT( decl ) = obj_rec_type;
3493 DECL_ARTIFICIAL( decl ) = DECL_IGNORED_P( decl ) = inherited;
3494 agg_layout.addField( decl, PTRSIZE);
3496 // Add the fields of each base class
3497 agg_layout.go();
3498 } else {
3499 ClassDeclaration * p = sym;
3500 while (p->baseclasses.dim) {
3501 p = ((BaseClass *) p->baseclasses.data[0])->base;
3503 DECL_FCONTEXT( vfield ) = TREE_TYPE( p->type->toCtype() );
3506 TYPE_CONTEXT( rec_type ) = gen.declContext(sym);
3508 agg_layout.finish(sym->attributes);
3511 return ctype;
3514 void
3515 ClassDeclaration::toDebug()
3517 tree rec_type = TREE_TYPE( type->toCtype() );
3518 /* Used to create BINFO even if debugging was off. This was needed to keep
3519 references to inherited types. */
3521 g.ofile->addAggMethods(rec_type, this);
3523 if ( ! isInterfaceDeclaration() )
3524 TYPE_BINFO( rec_type ) = binfo_for(NULL_TREE, this);
3525 else {
3526 unsigned offset = 0;
3527 BaseClass bc;
3528 bc.base = this;
3529 TYPE_BINFO( rec_type ) = intfc_binfo_for(NULL_TREE, this, offset);
3532 g.ofile->declareType(rec_type, this);
3535 void
3536 LabelStatement::toIR(IRState* irs)
3538 FuncDeclaration * func = irs->func;
3539 LabelDsymbol * label = isReturnLabel ? func->returnLabel : func->searchLabel(ident);
3540 tree t = irs->getLabelTree( label );
3542 if (t) {
3543 irs->doLabel(t);
3544 if (label->asmLabelNum)
3545 d_expand_priv_asm_label(irs, label->asmLabelNum);
3547 if (isReturnLabel && func->fensure)
3548 func->fensure->toIR(irs);
3549 else if (statement)
3550 statement->toIR(irs);
3552 // else, there was an error
3555 void
3556 GotoStatement::toIR(IRState* irs)
3558 g.ofile->setLoc(loc); /* This makes the 'undefined label' error show up on the correct line...
3559 The extra doLineNote in doJump shouldn't cause a problem. */
3560 tree t = irs->getLabelTree( label );
3561 if (t)
3562 irs->doJump(this, t);
3563 // else, there was an error
3566 void
3567 GotoCaseStatement::toIR(IRState * irs)
3569 // assumes cblocks have been set in SwitchStatement::toIR
3570 irs->doJump(this, cs->cblock);
3573 void
3574 GotoDefaultStatement::toIR(IRState * irs)
3576 // assumes cblocks have been set in SwitchStatement::toIR
3577 irs->doJump(this, sw->sdefault->cblock);
3580 void
3581 SwitchErrorStatement::toIR(IRState* irs)
3583 irs->doLineNote( loc );
3584 irs->doExp( irs->assertCall(loc, LIBCALL_SWITCH_ERROR) );
3587 void
3588 VolatileStatement::toIR(IRState* irs)
3590 irs->pushVolatile();
3591 statement->toIR( irs );
3592 irs->popVolatile();
3595 void
3596 ThrowStatement::toIR(IRState* irs)
3598 ClassDeclaration * class_decl = exp->type->toBasetype()->isClassHandle();
3599 // Front end already checks for isClassHandle
3600 InterfaceDeclaration * intfc_decl = class_decl->isInterfaceDeclaration();
3602 tree arg = exp->toElem(irs);
3604 if (intfc_decl) {
3605 if ( ! intfc_decl->isCOMclass()) {
3606 arg = irs->convertTo(arg, exp->type, irs->getObjectType());
3607 } else {
3608 error("cannot throw COM interfaces");
3612 irs->doLineNote(loc);
3613 irs->doExp( irs->libCall(LIBCALL_THROW, 1, & arg) );
3614 // %%TODO: somehow indicate flow stops here? -- set attribute noreturn on _d_throw
3617 void
3618 TryFinallyStatement::toIR(IRState * irs)
3620 // %% doc: this is not the same as a start_eh/end_eh_cleanup sequence
3621 tree t_body = body ? irs->makeStmtExpr(body) : d_void_zero_node;
3622 tree t_finl = finalbody ? irs->makeStmtExpr(finalbody) : d_void_zero_node;
3623 tree tf = build(TRY_FINALLY_EXPR, void_type_node, t_body, t_finl);
3624 // TREE_SIDE_EFFECTS(tf) = 1; // probably not needed
3625 irs->doLineNote(loc);
3626 irs->doExp(tf);
3629 void
3630 TryCatchStatement::toIR(IRState * irs)
3632 irs->doLineNote(loc);
3633 irs->startTry(this);
3634 if (body)
3635 body->toIR(irs);
3636 irs->startCatches();
3637 if (catches) {
3638 for (unsigned i = 0; i < catches->dim; i++) {
3639 Catch * a_catch = (Catch *) catches->data[i];
3641 irs->startCatch(a_catch->type->toCtype()); //expand_start_catch( xxx );
3643 irs->doLineNote(a_catch->loc);
3644 irs->startScope();
3646 if ( a_catch->var ) {
3647 tree exc_obj = irs->convertTo(irs->exceptionObject(),
3648 irs->getObjectType(), a_catch->type);
3649 // need to override initializer...
3650 // set DECL_INITIAL now and emitLocalVar will know not to change it
3651 DECL_INITIAL( a_catch->var->toSymbol()->Stree ) = exc_obj;
3652 irs->emitLocalVar(a_catch->var);
3655 if (a_catch->handler)
3656 a_catch->handler->toIR(irs);
3657 irs->endScope();
3658 irs->endCatch();
3661 irs->endCatches();
3664 void
3665 OnScopeStatement::toIR(IRState *)
3667 // nothing (?)
3670 void
3671 WithStatement::toIR(IRState * irs)
3673 if (wthis) {
3674 irs->startScope();
3675 irs->emitLocalVar(wthis);
3677 body->toIR(irs);
3678 if (wthis) {
3679 irs->endScope();
3683 void
3684 SynchronizedStatement::toIR(IRState * irs)
3686 if (exp) {
3687 InterfaceDeclaration * iface;
3689 irs->startBindings();
3690 tree decl = irs->localVar(IRState::getObjectType());
3692 DECL_IGNORED_P( decl ) = 1;
3693 tree cleanup = irs->libCall(LIBCALL_MONITOREXIT, 1, & decl);
3694 // assuming no conversions needed
3695 tree init_exp;
3697 assert(exp->type->toBasetype()->ty == Tclass);
3698 iface = ((TypeClass *) exp->type->toBasetype())->sym->isInterfaceDeclaration();
3699 if (iface) {
3700 if (! iface->isCOMclass()) {
3701 init_exp = irs->convertTo(exp, irs->getObjectType());
3702 } else {
3703 error("cannot synchronize on a COM interface");
3704 init_exp = error_mark_node;
3706 } else {
3707 init_exp = exp->toElem(irs);
3710 DECL_INITIAL(decl) = init_exp;
3712 irs->doLineNote(loc);
3714 #if D_GCC_VER < 40
3715 irs->expandDecl(decl);
3716 irs->doExp( irs->libCall(LIBCALL_MONITORENTER, 1, & decl));
3717 expand_decl_cleanup(decl, cleanup); // nope,nope just do it diffrent ways or just jump the cleanup like below..
3718 if (body)
3719 body->toIR( irs );
3720 #else
3721 irs->expandDecl(decl);
3722 irs->doExp( irs->libCall(LIBCALL_MONITORENTER, 1, & decl));
3723 irs->startTry(this);
3724 if (body)
3725 body->toIR( irs );
3726 irs->startFinally();
3727 irs->doExp( cleanup );
3728 irs->endFinally();
3729 #endif
3730 irs->endBindings();
3731 } else {
3732 #ifndef D_CRITSEC_SIZE
3733 #define D_CRITSEC_SIZE 64
3734 #endif
3735 static tree critsec_type = 0;
3737 if (! critsec_type ) {
3738 critsec_type = irs->arrayType(Type::tuns8, D_CRITSEC_SIZE);
3741 tree critsec_decl = build_decl(VAR_DECL, NULL_TREE, critsec_type);
3742 // name is only used to prevent ICEs
3743 g.ofile->giveDeclUniqueName(critsec_decl, "__critsec");
3744 tree critsec_ref = irs->addressOf(critsec_decl); // %% okay to use twice?
3745 dkeep(critsec_decl);
3747 TREE_STATIC(critsec_decl) = 1;
3748 TREE_PRIVATE(critsec_decl) = 1;
3749 DECL_ARTIFICIAL(critsec_decl) = 1;
3750 DECL_IGNORED_P(critsec_decl) = 1;
3752 g.ofile->rodc(critsec_decl, 1);
3754 #if D_GCC_VER < 40
3755 expand_eh_region_start();
3756 expand_expr_stmt_value(irs->libCall(LIBCALL_CRITICALENTER, 1, & critsec_ref), 0, 1);
3757 if (body)
3758 body->toIR( irs );
3759 expand_expr_stmt_value(irs->libCall(LIBCALL_CRITICALEXIT, 1, & critsec_ref), 0, 1);
3760 expand_eh_region_end_cleanup(irs->libCall(LIBCALL_CRITICALEXIT, 1, & critsec_ref));
3761 #else
3762 irs->startTry(this);
3763 irs->doExp( irs->libCall(LIBCALL_CRITICALENTER, 1, & critsec_ref) );
3764 if (body)
3765 body->toIR( irs );
3766 irs->startFinally();
3767 irs->doExp( irs->libCall(LIBCALL_CRITICALEXIT, 1, & critsec_ref) );
3768 irs->endFinally();
3769 #endif
3773 void
3774 ContinueStatement::toIR(IRState* irs)
3776 irs->doLineNote(loc);
3777 irs->continueLoop(ident);
3780 void
3781 BreakStatement::toIR(IRState* irs)
3783 irs->doLineNote(loc);
3784 irs->exitLoop(ident);
3787 void
3788 ReturnStatement::toIR(IRState* irs)
3790 irs->doLineNote(loc);
3792 if (exp) {
3793 if (exp->type->toBasetype()->ty != Tvoid) { // %% == Type::tvoid ?
3794 FuncDeclaration * func = irs->func;
3795 Type * ret_type = func->tintro ?
3796 func->tintro->nextOf() : func->type->nextOf();
3798 if (func->isMain() && ret_type->toBasetype()->ty == Tvoid)
3799 ret_type = Type::tint32;
3801 tree result_decl = DECL_RESULT( irs->func->toSymbol()->Stree );
3802 tree result_assign = build ( MODIFY_EXPR,
3803 TREE_TYPE( result_decl ), result_decl,
3804 // %% convert for init -- if we were returning a reference,
3805 // would want to take the address...
3806 irs->convertForAssignment(exp, (Type*)ret_type) );
3808 irs->doReturn(result_assign); // expand_return(result_assign);
3809 } else {
3810 //irs->doExp(exp);
3811 irs->doReturn(NULL_TREE);
3813 } else {
3814 irs->doReturn(NULL_TREE);
3818 void
3819 DefaultStatement::toIR(IRState * irs)
3821 irs->doCase(NULL_TREE, cblock);
3822 if (statement)
3823 statement->toIR( irs );
3826 void
3827 CaseStatement::toIR(IRState * irs)
3829 tree case_value;
3831 if ( exp->type->isscalar() )
3832 case_value = exp->toElem(irs);
3833 else
3834 case_value = irs->integerConstant(index, Type::tint32);
3835 irs->doCase(case_value, cblock);
3836 if (statement)
3837 statement->toIR( irs );
3840 void
3841 SwitchStatement::toIR(IRState * irs)
3843 tree cond_tree;
3844 // %% also what about c-semantics doing emit_nop() ?
3845 irs->doLineNote( loc );
3847 cond_tree = condition->toElem( irs );
3849 Type * cond_type = condition->type->toBasetype();
3850 if (cond_type->ty == Tarray) {
3851 Type * elem_type = cond_type->nextOf()->toBasetype();
3852 LibCall lib_call;
3853 switch (elem_type->ty) {
3854 case Tchar: lib_call = LIBCALL_SWITCH_STRING; break;
3855 case Twchar: lib_call = LIBCALL_SWITCH_USTRING; break;
3856 case Tdchar: lib_call = LIBCALL_SWITCH_DSTRING; break;
3857 default:
3858 ::error("switch statement value must be an array of some character type, not %s", elem_type->toChars());
3859 abort();
3862 // Apparently the backend is supposed to sort and set the indexes
3863 // on the case array
3864 // have to change them to be useable
3865 cases->sort(); // %%!!
3867 Symbol * s = static_sym();
3868 dt_t ** pdt = & s->Sdt;
3869 s->Sseg = CDATA;
3870 for (unsigned case_i = 0; case_i < cases->dim; case_i++) {
3871 CaseStatement * case_stmt = (CaseStatement *) cases->data[case_i];
3872 pdt = case_stmt->exp->toDt( pdt );
3873 case_stmt->index = case_i;
3875 outdata(s);
3876 tree p_table = irs->addressOf(s->Stree);
3878 tree args[2] = {
3879 irs->darrayVal(cond_type->arrayOf()->toCtype(), cases->dim,
3880 p_table),
3881 cond_tree };
3883 cond_tree = irs->libCall(lib_call, 2, args);
3884 } else if (! cond_type->isscalar()) {
3885 ::error("cannot handle switch condition of type %s", cond_type->toChars());
3886 abort();
3889 // Build LABEL_DECLs now so they can be refered to by goto case
3890 if (cases) {
3891 for (unsigned i = 0; i < cases->dim; i++) {
3892 CaseStatement * case_stmt = (CaseStatement *) cases->data[i];
3893 case_stmt->cblock = irs->label(case_stmt->loc); //make_case_label(case_stmt->loc);
3895 if (sdefault)
3896 sdefault->cblock = irs->label(sdefault->loc); //make_case_label(sdefault->loc);
3899 cond_tree = fold(cond_tree);
3900 irs->startCase(this, cond_tree);
3901 if (body)
3902 body->toIR( irs );
3903 irs->endCase(cond_tree);
3907 void
3908 Statement::toIR(IRState*)
3910 ::error("Statement::toIR: don't know what to do (%s)", toChars());
3911 abort();
3914 void
3915 IfStatement::toIR(IRState * irs)
3917 if (match) {
3918 irs->startScope();
3919 irs->emitLocalVar(match);
3921 irs->startCond(this, condition);
3922 if (ifbody)
3923 ifbody->toIR( irs );
3924 if ( elsebody ) {
3925 irs->startElse();
3926 elsebody->toIR ( irs );
3928 irs->endCond();
3929 if (match)
3930 irs->endScope();
3933 void
3934 ForeachStatement::toIR(IRState* irs)
3936 // %% better?: set iter to start - 1 and use result of increment for condition?
3938 // side effects?
3940 Type * agg_type = aggr->type->toBasetype();
3941 Type * elem_type = agg_type->nextOf()->toBasetype();
3942 tree iter_decl;
3943 tree bound_expr;
3944 tree iter_init_expr;
3945 tree aggr_expr = irs->maybeMakeTemp( aggr->toElem(irs) );
3947 assert(value);
3949 gcc_assert(elem_type->ty != Tbit);
3951 irs->startScope();
3952 irs->startBindings(); /* Variables created by the function will probably
3953 end up in a contour created by emitLocalVar. This
3954 startBindings call is just to be safe */
3955 irs->doLineNote( loc );
3957 Loc default_loc;
3958 if (loc.filename)
3959 default_loc = loc;
3960 else {
3961 fprintf(stderr, "EXPER: I need this\n");
3962 default_loc = Loc(g.mod, 1); // %% fix
3965 if (! value->loc.filename)
3966 g.ofile->setDeclLoc( value->toSymbol()->Stree, default_loc );
3968 irs->emitLocalVar(value, true);
3970 if (key) {
3971 if (! key->loc.filename)
3972 g.ofile->setDeclLoc( key->toSymbol()->Stree, default_loc );
3973 if (! key->init)
3974 DECL_INITIAL( key->toSymbol()->Stree ) = op == TOKforeach ?
3975 irs->integerConstant(0, key->type) :
3976 irs->arrayLength(aggr_expr, agg_type);
3978 irs->emitLocalVar(key); // %% getExpInitializer causes uneeded initialization
3981 bool iter_is_value;
3982 if (value->isRef() || value->isOut()) {
3983 iter_is_value = true;
3984 iter_decl = irs->var(value);
3985 } else {
3986 iter_is_value = false;
3987 iter_decl = irs->localVar(elem_type->pointerTo());
3988 irs->expandDecl(iter_decl);
3991 if ( agg_type->ty == Tsarray) {
3992 bound_expr = ((TypeSArray *) agg_type)->dim->toElem(irs);
3993 iter_init_expr = irs->addressOf( aggr_expr );
3994 // Type needs to be pointer-to-element to get pointerIntSum
3995 // to work
3996 iter_init_expr = irs->nop(iter_init_expr,
3997 agg_type->nextOf()->pointerTo()->toCtype());
3998 } else {
3999 bound_expr = irs->darrayLenRef( aggr_expr );
4000 iter_init_expr = irs->darrayPtrRef( aggr_expr );
4002 iter_init_expr = save_expr( iter_init_expr );
4003 bound_expr = irs->pointerIntSum(iter_init_expr, bound_expr);
4004 // aggr. isn't supposed to be modified, so...
4005 bound_expr = save_expr( bound_expr );
4007 enum tree_code iter_op = PLUS_EXPR;
4009 if (op == TOKforeach_reverse)
4011 tree t = iter_init_expr;
4012 iter_init_expr = bound_expr;
4013 bound_expr = t;
4015 iter_op = MINUS_EXPR;
4018 tree condition = build(NE_EXPR, boolean_type_node, iter_decl, bound_expr);
4019 tree incr_expr =
4020 build(MODIFY_EXPR, void_type_node, iter_decl,
4021 build(iter_op, TREE_TYPE(iter_decl), iter_decl,
4022 size_int(elem_type->size())));
4023 if (key) {
4024 tree key_decl = irs->var(key);
4025 tree key_incr_expr =
4026 build(MODIFY_EXPR, void_type_node, key_decl,
4027 build(iter_op, TREE_TYPE(key_decl), key_decl,
4028 irs->integerConstant(1, TREE_TYPE(key_decl))));
4029 incr_expr = irs->compound(incr_expr, key_incr_expr);
4032 irs->doExp( build(MODIFY_EXPR, void_type_node, iter_decl, iter_init_expr) );
4034 irs->startLoop(this);
4035 irs->exitIfFalse(condition);
4036 if ( op == TOKforeach_reverse )
4037 irs->doExp( incr_expr );
4038 if ( ! iter_is_value )
4039 irs->doExp( build(MODIFY_EXPR, void_type_node, irs->var(value),
4040 irs->indirect(iter_decl)) );
4041 if (body)
4042 body->toIR( irs );
4043 irs->continueHere();
4045 if ( op == TOKforeach )
4046 irs->doExp( incr_expr );
4048 irs->endLoop();
4050 irs->endBindings(); // not really needed
4051 irs->endScope();
4054 #if V2
4056 void
4057 ForeachRangeStatement::toIR(IRState * irs)
4059 bool fwd = op == TOKforeach;
4061 irs->startScope();
4062 irs->startBindings(); /* Variables created by the function will probably
4063 end up in a contour created by emitLocalVar. This
4064 startBindings call is just to be safe */
4065 irs->doLineNote( loc );
4067 gcc_assert(key != NULL);
4068 gcc_assert(lwr != NULL);
4069 gcc_assert(upr != NULL);
4071 // Front end ensures no storage class
4072 irs->emitLocalVar(key, true);
4073 tree key_decl = irs->var(key);
4074 tree lwr_decl = irs->localVar(lwr->type);
4075 tree upr_decl = irs->localVar(upr->type);
4076 tree iter_expr = irs->vmodify(key_decl,
4077 build2(fwd ? PLUS_EXPR : MINUS_EXPR, TREE_TYPE(key_decl),
4078 key_decl, irs->integerConstant(1, TREE_TYPE(key_decl))));
4079 tree condition;
4081 irs->expandDecl(lwr_decl);
4082 irs->expandDecl(upr_decl);
4083 irs->doExp( irs->vmodify(lwr_decl, lwr->toElem(irs)) );
4084 irs->doExp( irs->vmodify(upr_decl, upr->toElem(irs)) );
4086 condition = build2(fwd ? LT_EXPR : GT_EXPR, boolean_type_node,
4087 key_decl, fwd ? upr_decl : lwr_decl);
4089 irs->doExp( irs->vmodify(key_decl, fwd ? lwr_decl : upr_decl) );
4091 irs->startLoop(this);
4092 if (! fwd)
4093 irs->continueHere();
4094 irs->exitIfFalse(condition);
4095 if (! fwd)
4096 irs->doExp(iter_expr);
4097 if (body)
4098 body->toIR( irs );
4099 if ( fwd ) {
4100 irs->continueHere();
4101 irs->doExp(iter_expr);
4103 irs->endLoop();
4105 irs->endBindings(); // not really needed
4106 irs->endScope();
4109 #endif
4111 void
4112 ForStatement::toIR(IRState * irs)
4114 irs->doLineNote(loc);
4115 // %% scope
4116 if (init)
4117 init->toIR( irs );
4118 irs->startLoop(this);
4119 if (condition)
4120 irs->exitIfFalse(condition);
4121 if (body)
4122 body->toIR( irs );
4123 irs->continueHere();
4124 if (increment)
4125 irs->doExp(increment->toElem(irs)); // force side effects?
4126 irs->endLoop();
4129 void
4130 DoStatement::toIR(IRState * irs)
4132 irs->doLineNote(loc);
4133 irs->startLoop(this);
4134 if (body)
4135 body->toIR( irs );
4136 irs->continueHere();
4137 irs->exitIfFalse(condition);
4138 irs->endLoop();
4141 void
4142 WhileStatement::toIR(IRState* irs)
4144 irs->doLineNote(loc); // store for next statement...
4145 irs->startLoop(this);
4146 irs->continueHere();
4147 irs->exitIfFalse(condition, 1); // 1 == is topcond .. good as deprecated..
4148 if (body)
4149 body->toIR( irs );
4150 irs->endLoop();
4153 void
4154 ScopeStatement::toIR(IRState* irs)
4156 if (statement) {
4157 irs->startScope();
4158 statement->toIR( irs );
4159 irs->endScope();
4163 void
4164 CompoundStatement::toIR(IRState* irs)
4166 if (statements) {
4167 for (unsigned i = 0; i < statements->dim; i++) {
4168 Statement * statement = (Statement *) statements->data[i];
4170 if (statement)
4171 statement->toIR(irs);
4176 void
4177 UnrolledLoopStatement::toIR(IRState* irs)
4179 if (statements) {
4180 irs->startLoop(this);
4181 irs->continueHere();
4182 for (unsigned i = 0; i < statements->dim; i++) {
4183 Statement * statement = (Statement *) statements->data[i];
4185 if (statement)
4187 irs->setContinueLabel( irs->label(loc) );
4188 statement->toIR(irs);
4189 irs->continueHere();
4192 irs->exitLoop(NULL);
4193 irs->endLoop();
4197 void
4198 ExpStatement::toIR(IRState * irs)
4200 if (exp) {
4201 gen.doLineNote(loc);
4203 tree exp_tree = exp->toElem(irs);
4205 irs->doExp(exp_tree);
4206 } else {
4207 // nothing
4211 #if V2
4212 void
4213 PragmaStatement::toIR(IRState *)
4215 // nothing
4217 #endif
4219 void
4220 EnumDeclaration::toDebug()
4226 Dsymbol::cvMember(unsigned char*)
4228 return 0;
4231 EnumDeclaration::cvMember(unsigned char*)
4233 return 0;
4236 FuncDeclaration::cvMember(unsigned char*)
4238 return 0;
4241 VarDeclaration::cvMember(unsigned char*)
4243 return 0;
4246 TypedefDeclaration::cvMember(unsigned char*)
4248 return 0;
4251 #if D_GCC_VER < 40
4254 d_expand_expr(tree exp, rtx target , enum machine_mode tmode, int modifier, rtx *)
4256 if ( TREE_CODE(exp) == (enum tree_code) D_STMT_EXPR ) {
4257 IRState * irs;
4258 Statement * stmt;
4260 gen.retrieveStmtExpr(exp, & stmt, & irs);
4261 // need push_temp_slots()?
4263 tree rtl_expr = expand_start_stmt_expr(1);
4264 // This startBindings call is needed so get_last_insn() doesn't return NULL
4265 // in expand_start_case().
4266 irs->startBindings();
4267 // preserve_temp_slots as in c-common.c:c_expand_expr
4269 stmt->toIR(irs);
4270 irs->endBindings();
4272 expand_end_stmt_expr (rtl_expr);
4274 rtx result = expand_expr (rtl_expr, target, tmode, (enum expand_modifier) modifier);
4275 pop_temp_slots();
4276 return result;
4277 } else if ( TREE_CODE(exp) == (enum tree_code) D_ARRAY_SET_EXPR ){
4278 // %% if single byte element, expand to memset
4280 assert( POINTER_TYPE_P( TREE_TYPE( TREE_OPERAND( exp, 0 ))));
4281 assert( INTEGRAL_TYPE_P( TREE_TYPE( TREE_OPERAND( exp, 2 ))));
4282 // assuming unsigned source is unsigned
4284 push_temp_slots (); // will this work? maybe expand_start_binding
4285 tree rtl_expr = expand_start_stmt_expr(1);
4287 do_array_set(g.irs, // %% fix!
4288 TREE_OPERAND(exp, 0), TREE_OPERAND(exp, 1), TREE_OPERAND(exp, 2));
4290 expand_end_stmt_expr(rtl_expr);
4291 rtx result = expand_expr(rtl_expr, target, tmode, (enum expand_modifier) modifier);
4292 pop_temp_slots ();
4293 return result;
4294 } else {
4295 abort();
4299 #endif
4300 /*else..
4301 void x(tree ptr, tree src, tree count) {
4302 tree count_var =;
4303 tree ptr_var = ;
4304 build(BIND_EXPR, count_var, t_loop, block???0
4308 static tree
4309 d_build_eh_type_type(tree type)
4311 TypeClass * d_type = (TypeClass *) IRState::getDType(type);
4312 assert(d_type);
4313 d_type = (TypeClass *) d_type->toBasetype();
4314 assert(d_type->ty == Tclass);
4315 return IRState::addressOf( d_type->sym->toSymbol()->Stree );
4318 tree d_void_zero_node;
4320 tree d_null_pointer;
4321 tree d_vtbl_ptr_type_node;
4323 void
4324 gcc_d_backend_init()
4326 // %% need this here to add the type decls ...
4327 init_global_binding_level();
4329 // This allows the code in d-builtins2 to not have to worry about
4330 // converting (C signed char *) to (D char *) for string arguments of
4331 // built-in functions.
4332 flag_signed_char = 0;
4333 // This is required or we'll crash pretty early on. %%log
4334 build_common_tree_nodes (flag_signed_char
4335 #if D_GCC_VER >= 40
4336 , false
4337 #endif
4340 // This is also required (or the manual equivalent) or crashes
4341 // will occur later
4342 size_type_node = d_type_for_mode(ptr_mode, 1);
4344 // c was: TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
4345 //signed_size_type_node = c_common_signed_type (size_type_node);
4347 // If this is called after the next statements, you'll get an ICE.
4348 set_sizetype(size_type_node);
4351 // need this for void.. %% but this crashes... probably need to impl
4352 // some things in dc-lang.cc
4353 build_common_tree_nodes_2 (0 /* %% support the option */);
4355 // Specific to D (but so far all taken from C)
4356 #if D_GCC_VER < 40
4357 d_void_zero_node = build_int_2 (0, 0);
4358 TREE_TYPE (d_void_zero_node) = void_type_node;
4359 #else
4360 d_void_zero_node = build_int_cst (void_type_node, 0);
4361 #endif
4362 // %%TODO: we are relying on default boolean_type_node being 8bit / same as Tbit
4364 d_null_pointer = convert(ptr_type_node, integer_zero_node);
4366 TYPE_NAME( integer_type_node ) = build_decl(TYPE_DECL, get_identifier("int"), integer_type_node);
4367 TYPE_NAME( char_type_node ) = build_decl(TYPE_DECL, get_identifier("cchar"), char_type_node); // "char?"
4369 REALSIZE = int_size_in_bytes(long_double_type_node);
4370 REALPAD = 0;
4371 PTRSIZE = int_size_in_bytes(ptr_type_node);
4372 switch (int_size_in_bytes(size_type_node)) {
4373 case 4:
4374 Tsize_t = Tuns32;
4375 Tindex = Tint32;
4376 break;
4377 case 8:
4378 Tsize_t = Tuns64;
4379 Tindex = Tint64;
4380 break;
4381 default:
4382 abort();
4384 switch ( PTRSIZE ) {
4385 case 4:
4386 assert(POINTER_SIZE == 32);
4387 Tptrdiff_t = Tint32;
4388 break;
4389 case 8:
4390 assert(POINTER_SIZE == 64);
4391 Tptrdiff_t = Tint64;
4392 break;
4393 default:
4394 abort();
4396 #if V2
4397 CLASSINFO_SIZE = 19 * PTRSIZE;
4398 #else
4399 CLASSINFO_SIZE = 18 * PTRSIZE;
4400 #endif
4402 d_init_builtins();
4404 if (flag_exceptions) {
4405 eh_personality_libfunc = init_one_libfunc(d_using_sjlj_exceptions()
4406 ? "__gdc_personality_sj0" : "__gdc_personality_v0");
4407 #if D_GCC_VER >= 41
4408 default_init_unwind_resume_libfunc ();
4409 #endif
4410 lang_eh_runtime_type = d_build_eh_type_type;
4411 using_eh_for_cleanups ();
4412 // lang_proctect_cleanup_actions = ...; // no need? ... probably needed for autos
4415 /* copied and modified from cp/decl.c; only way for vtable to work in gdb... */
4416 // or not, I'm feeling very confused...
4417 if (1) {
4418 /* Make sure we get a unique function type, so we can give
4419 its pointer type a name. (This wins for gdb.) */
4420 tree vfunc_type = make_node (FUNCTION_TYPE);
4421 TREE_TYPE (vfunc_type) = Type::tint32->toCtype(); // integer_type_node; messed up built in types?
4422 TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
4423 layout_type (vfunc_type);
4425 tree vtable_entry_type = build_pointer_type (vfunc_type);
4426 d_vtbl_ptr_type_node = build_pointer_type(vtable_entry_type);
4427 layout_type (d_vtbl_ptr_type_node);// %%TODO: check if needed
4430 // This also allows virtual functions to be called, but when vtbl entries,
4431 // are inspected, function symbol names do not appear.
4432 // d_vtbl_ptr_type_node = Type::tvoid->pointerTo()->pointerTo()->toCtype();
4434 // This is the C main, not the D main
4435 main_identifier_node = get_identifier ("main");
4438 void
4439 gcc_d_backend_term()