Allow returning something of type void in a function that returns void
[delight/core.git] / d-glue.cc
blobdbccf612673a5f23f8377adc91e911002be1ec7b
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 TypeMaybe::toCtype()
3319 if (! ctype)
3320 ctype = next->toCtype();
3321 return ctype;
3324 type *
3325 TypeDelegate::toCtype()
3327 if (! ctype) {
3328 assert(next->toBasetype()->ty == Tfunction);
3329 ctype = gen.twoFieldType(Type::tvoid->pointerTo(), next->pointerTo(),
3330 this, "object", "func");
3331 dkeep(ctype);
3333 return ctype;
3336 /* Create debug information for a ClassDeclaration's inheritance tree.
3337 Interfaces are not included. */
3338 static tree
3339 binfo_for(tree tgt_binfo, ClassDeclaration * cls)
3341 tree binfo =
3342 #if D_GCC_VER < 40
3343 make_tree_vec(BINFO_ELTS)
3344 #else
3345 make_tree_binfo(1)
3346 #endif
3348 TREE_TYPE (binfo) = TREE_TYPE( cls->type->toCtype() ); // RECORD_TYPE, not REFERENCE_TYPE
3349 BINFO_INHERITANCE_CHAIN(binfo) = tgt_binfo;
3350 BINFO_OFFSET (binfo) = size_zero_node; // %% type?, otherwize, integer_zero_node
3352 if (cls->baseClass) {
3353 #if D_GCC_VER < 40
3354 BINFO_BASETYPES(binfo) = make_tree_vec(1);
3355 BINFO_BASETYPE(binfo, 0) = binfo_for(binfo, cls->baseClass);
3356 #else
3357 BINFO_BASE_APPEND(binfo, binfo_for(binfo, cls->baseClass));
3358 #endif
3359 #ifdef BINFO_BASEACCESSES
3360 #if D_GCC_VER >= 40
3361 #error update vector stuff
3362 #endif
3363 tree prot_tree;
3365 BINFO_BASEACCESSES(binfo) = make_tree_vec(1);
3366 switch ( ((BaseClass *) cls->baseclasses.data[0])->protection ) {
3367 case PROTpublic:
3368 prot_tree = access_public_node;
3369 break;
3370 case PROTprotected:
3371 prot_tree = access_protected_node;
3372 break;
3373 case PROTprivate:
3374 prot_tree = access_private_node;
3375 break;
3376 default:
3377 prot_tree = access_public_node;
3378 break;
3380 BINFO_BASEACCESS(binfo,0) = prot_tree;
3381 #endif
3384 return binfo;
3387 /* Create debug information for an InterfaceDeclaration's inheritance
3388 tree. In order to access all inherited methods in the debugger,
3389 the entire tree must be described.
3391 This function makes assumptions about inherface layout. */
3392 static tree
3393 intfc_binfo_for(tree tgt_binfo, ClassDeclaration * iface, unsigned & inout_offset)
3395 tree binfo =
3396 #if D_GCC_VER < 40
3397 make_tree_vec(BINFO_ELTS)
3398 #else
3399 make_tree_binfo(iface->baseclasses.dim)
3400 #endif
3402 TREE_TYPE (binfo) = TREE_TYPE( iface->type->toCtype() ); // RECORD_TYPE, not REFERENCE_TYPE
3403 BINFO_INHERITANCE_CHAIN(binfo) = tgt_binfo;
3404 BINFO_OFFSET (binfo) = size_int(inout_offset * PTRSIZE);
3406 if (iface->baseclasses.dim) {
3407 #if D_GCC_VER < 40
3408 BINFO_BASETYPES(binfo) = make_tree_vec(iface->baseclasses.dim);
3409 #endif
3410 #ifdef BINFO_BASEACCESSES
3411 BINFO_BASEACCESSES(binfo) = make_tree_vec(iface->baseclasses.dim);
3412 #endif
3414 for (unsigned i = 0; i < iface->baseclasses.dim; i++) {
3415 BaseClass * bc = (BaseClass *) iface->baseclasses.data[i];
3417 if (i)
3418 inout_offset++;
3420 #if D_GCC_VER < 40
3421 BINFO_BASETYPE(binfo, i) = intfc_binfo_for(binfo, bc->base, inout_offset);
3422 #else
3423 BINFO_BASE_APPEND(binfo, intfc_binfo_for(binfo, bc->base, inout_offset));
3424 #endif
3425 #ifdef BINFO_BASEACCESSES
3426 tree prot_tree;
3427 switch ( bc->protection ) {
3428 case PROTpublic:
3429 prot_tree = access_public_node;
3430 break;
3431 case PROTprotected:
3432 prot_tree = access_protected_node;
3433 break;
3434 case PROTprivate:
3435 prot_tree = access_private_node;
3436 break;
3437 default:
3438 prot_tree = access_public_node;
3439 break;
3441 BINFO_BASEACCESS(binfo, i) = prot_tree;
3442 #endif
3445 return binfo;
3448 type *
3449 TypeClass::toCtype()
3451 if (! ctype) {
3452 tree rec_type;
3453 Array base_class_decls;
3454 bool inherited = sym->baseClass != 0;
3455 tree obj_rec_type;
3456 tree vfield;
3458 /* Need to set ctype right away in case of self-references to
3459 the type during this call. */
3460 rec_type = make_node( RECORD_TYPE );
3461 //apply_type_attributes(sym->attributes, rec_type, true);
3462 ctype = build_reference_type( rec_type );
3463 dkeep(ctype); // because BINFO moved out to toDebug
3464 g.ofile->initTypeDecl(rec_type, sym);
3466 obj_rec_type = TREE_TYPE( gen.getObjectType()->toCtype() );
3468 // Note that this is set on the reference type, not the record type.
3469 TYPE_LANG_SPECIFIC( ctype ) = build_d_type_lang_specific( this );
3471 AggLayout agg_layout(sym, rec_type);
3473 // Most of this silly code is just to produce correct debugging information.
3475 /* gdb apparently expects the vtable field to be named
3476 "_vptr$...." (stabsread.c) Otherwise, the debugger gives
3477 lots of annoying error messages. C++ appends the class
3478 name of the first base witht that field after the '$'. */
3479 /* update: annoying messages might not appear anymore after making
3480 other changes */
3481 // Add the virtual table pointer
3482 tree decl = build_decl(FIELD_DECL, get_identifier("_vptr$"), /*vtbl_type*/d_vtbl_ptr_type_node);
3483 agg_layout.addField( decl, 0 ); // %% target stuff..
3485 if (inherited) {
3486 vfield = copy_node( decl );
3487 DECL_ARTIFICIAL( decl ) = DECL_IGNORED_P( decl ) = 1;
3488 } else {
3489 vfield = decl;
3491 DECL_VIRTUAL_P( vfield ) = 1;
3492 TYPE_VFIELD( rec_type ) = vfield; // This only seems to affect debug info
3494 if (! sym->isInterfaceDeclaration()) {
3495 DECL_FCONTEXT( vfield ) = obj_rec_type;
3497 // Add the monitor
3498 // %% target type
3499 decl = build_decl(FIELD_DECL, get_identifier("_monitor"), ptr_type_node);
3500 DECL_FCONTEXT( decl ) = obj_rec_type;
3501 DECL_ARTIFICIAL( decl ) = DECL_IGNORED_P( decl ) = inherited;
3502 agg_layout.addField( decl, PTRSIZE);
3504 // Add the fields of each base class
3505 agg_layout.go();
3506 } else {
3507 ClassDeclaration * p = sym;
3508 while (p->baseclasses.dim) {
3509 p = ((BaseClass *) p->baseclasses.data[0])->base;
3511 DECL_FCONTEXT( vfield ) = TREE_TYPE( p->type->toCtype() );
3514 TYPE_CONTEXT( rec_type ) = gen.declContext(sym);
3516 agg_layout.finish(sym->attributes);
3519 return ctype;
3522 void
3523 ClassDeclaration::toDebug()
3525 tree rec_type = TREE_TYPE( type->toCtype() );
3526 /* Used to create BINFO even if debugging was off. This was needed to keep
3527 references to inherited types. */
3529 g.ofile->addAggMethods(rec_type, this);
3531 if ( ! isInterfaceDeclaration() )
3532 TYPE_BINFO( rec_type ) = binfo_for(NULL_TREE, this);
3533 else {
3534 unsigned offset = 0;
3535 BaseClass bc;
3536 bc.base = this;
3537 TYPE_BINFO( rec_type ) = intfc_binfo_for(NULL_TREE, this, offset);
3540 g.ofile->declareType(rec_type, this);
3543 void
3544 LabelStatement::toIR(IRState* irs)
3546 FuncDeclaration * func = irs->func;
3547 LabelDsymbol * label = isReturnLabel ? func->returnLabel : func->searchLabel(ident);
3548 tree t = irs->getLabelTree( label );
3550 if (t) {
3551 irs->doLabel(t);
3552 if (label->asmLabelNum)
3553 d_expand_priv_asm_label(irs, label->asmLabelNum);
3555 if (isReturnLabel && func->fensure)
3556 func->fensure->toIR(irs);
3557 else if (statement)
3558 statement->toIR(irs);
3560 // else, there was an error
3563 void
3564 GotoStatement::toIR(IRState* irs)
3566 g.ofile->setLoc(loc); /* This makes the 'undefined label' error show up on the correct line...
3567 The extra doLineNote in doJump shouldn't cause a problem. */
3568 tree t = irs->getLabelTree( label );
3569 if (t)
3570 irs->doJump(this, t);
3571 // else, there was an error
3574 void
3575 GotoCaseStatement::toIR(IRState * irs)
3577 // assumes cblocks have been set in SwitchStatement::toIR
3578 irs->doJump(this, cs->cblock);
3581 void
3582 GotoDefaultStatement::toIR(IRState * irs)
3584 // assumes cblocks have been set in SwitchStatement::toIR
3585 irs->doJump(this, sw->sdefault->cblock);
3588 void
3589 SwitchErrorStatement::toIR(IRState* irs)
3591 irs->doLineNote( loc );
3592 irs->doExp( irs->assertCall(loc, LIBCALL_SWITCH_ERROR) );
3595 void
3596 VolatileStatement::toIR(IRState* irs)
3598 irs->pushVolatile();
3599 statement->toIR( irs );
3600 irs->popVolatile();
3603 void
3604 ThrowStatement::toIR(IRState* irs)
3606 ClassDeclaration * class_decl = exp->type->toBasetype()->isClassHandle();
3607 // Front end already checks for isClassHandle
3608 InterfaceDeclaration * intfc_decl = class_decl->isInterfaceDeclaration();
3610 tree arg = exp->toElem(irs);
3612 if (intfc_decl) {
3613 if ( ! intfc_decl->isCOMclass()) {
3614 arg = irs->convertTo(arg, exp->type, irs->getObjectType());
3615 } else {
3616 error("cannot throw COM interfaces");
3620 irs->doLineNote(loc);
3621 irs->doExp( irs->libCall(LIBCALL_THROW, 1, & arg) );
3622 // %%TODO: somehow indicate flow stops here? -- set attribute noreturn on _d_throw
3625 void
3626 TryFinallyStatement::toIR(IRState * irs)
3628 // %% doc: this is not the same as a start_eh/end_eh_cleanup sequence
3629 tree t_body = body ? irs->makeStmtExpr(body) : d_void_zero_node;
3630 tree t_finl = finalbody ? irs->makeStmtExpr(finalbody) : d_void_zero_node;
3631 tree tf = build(TRY_FINALLY_EXPR, void_type_node, t_body, t_finl);
3632 // TREE_SIDE_EFFECTS(tf) = 1; // probably not needed
3633 irs->doLineNote(loc);
3634 irs->doExp(tf);
3637 void
3638 TryCatchStatement::toIR(IRState * irs)
3640 irs->doLineNote(loc);
3641 irs->startTry(this);
3642 if (body)
3643 body->toIR(irs);
3644 irs->startCatches();
3645 if (catches) {
3646 for (unsigned i = 0; i < catches->dim; i++) {
3647 Catch * a_catch = (Catch *) catches->data[i];
3649 irs->startCatch(a_catch->type->toCtype()); //expand_start_catch( xxx );
3651 irs->doLineNote(a_catch->loc);
3652 irs->startScope();
3654 if ( a_catch->var ) {
3655 tree exc_obj = irs->convertTo(irs->exceptionObject(),
3656 irs->getObjectType(), a_catch->type);
3657 // need to override initializer...
3658 // set DECL_INITIAL now and emitLocalVar will know not to change it
3659 DECL_INITIAL( a_catch->var->toSymbol()->Stree ) = exc_obj;
3660 irs->emitLocalVar(a_catch->var);
3663 if (a_catch->handler)
3664 a_catch->handler->toIR(irs);
3665 irs->endScope();
3666 irs->endCatch();
3669 irs->endCatches();
3672 void
3673 OnScopeStatement::toIR(IRState *)
3675 // nothing (?)
3678 void
3679 WithStatement::toIR(IRState * irs)
3681 if (wthis) {
3682 irs->startScope();
3683 irs->emitLocalVar(wthis);
3685 body->toIR(irs);
3686 if (wthis) {
3687 irs->endScope();
3691 void
3692 SynchronizedStatement::toIR(IRState * irs)
3694 if (exp) {
3695 InterfaceDeclaration * iface;
3697 irs->startBindings();
3698 tree decl = irs->localVar(IRState::getObjectType());
3700 DECL_IGNORED_P( decl ) = 1;
3701 tree cleanup = irs->libCall(LIBCALL_MONITOREXIT, 1, & decl);
3702 // assuming no conversions needed
3703 tree init_exp;
3705 assert(exp->type->toBasetype()->ty == Tclass);
3706 iface = ((TypeClass *) exp->type->toBasetype())->sym->isInterfaceDeclaration();
3707 if (iface) {
3708 if (! iface->isCOMclass()) {
3709 init_exp = irs->convertTo(exp, irs->getObjectType());
3710 } else {
3711 error("cannot synchronize on a COM interface");
3712 init_exp = error_mark_node;
3714 } else {
3715 init_exp = exp->toElem(irs);
3718 DECL_INITIAL(decl) = init_exp;
3720 irs->doLineNote(loc);
3722 #if D_GCC_VER < 40
3723 irs->expandDecl(decl);
3724 irs->doExp( irs->libCall(LIBCALL_MONITORENTER, 1, & decl));
3725 expand_decl_cleanup(decl, cleanup); // nope,nope just do it diffrent ways or just jump the cleanup like below..
3726 if (body)
3727 body->toIR( irs );
3728 #else
3729 irs->expandDecl(decl);
3730 irs->doExp( irs->libCall(LIBCALL_MONITORENTER, 1, & decl));
3731 irs->startTry(this);
3732 if (body)
3733 body->toIR( irs );
3734 irs->startFinally();
3735 irs->doExp( cleanup );
3736 irs->endFinally();
3737 #endif
3738 irs->endBindings();
3739 } else {
3740 #ifndef D_CRITSEC_SIZE
3741 #define D_CRITSEC_SIZE 64
3742 #endif
3743 static tree critsec_type = 0;
3745 if (! critsec_type ) {
3746 critsec_type = irs->arrayType(Type::tuns8, D_CRITSEC_SIZE);
3749 tree critsec_decl = build_decl(VAR_DECL, NULL_TREE, critsec_type);
3750 // name is only used to prevent ICEs
3751 g.ofile->giveDeclUniqueName(critsec_decl, "__critsec");
3752 tree critsec_ref = irs->addressOf(critsec_decl); // %% okay to use twice?
3753 dkeep(critsec_decl);
3755 TREE_STATIC(critsec_decl) = 1;
3756 TREE_PRIVATE(critsec_decl) = 1;
3757 DECL_ARTIFICIAL(critsec_decl) = 1;
3758 DECL_IGNORED_P(critsec_decl) = 1;
3760 g.ofile->rodc(critsec_decl, 1);
3762 #if D_GCC_VER < 40
3763 expand_eh_region_start();
3764 expand_expr_stmt_value(irs->libCall(LIBCALL_CRITICALENTER, 1, & critsec_ref), 0, 1);
3765 if (body)
3766 body->toIR( irs );
3767 expand_expr_stmt_value(irs->libCall(LIBCALL_CRITICALEXIT, 1, & critsec_ref), 0, 1);
3768 expand_eh_region_end_cleanup(irs->libCall(LIBCALL_CRITICALEXIT, 1, & critsec_ref));
3769 #else
3770 irs->startTry(this);
3771 irs->doExp( irs->libCall(LIBCALL_CRITICALENTER, 1, & critsec_ref) );
3772 if (body)
3773 body->toIR( irs );
3774 irs->startFinally();
3775 irs->doExp( irs->libCall(LIBCALL_CRITICALEXIT, 1, & critsec_ref) );
3776 irs->endFinally();
3777 #endif
3781 void
3782 ContinueStatement::toIR(IRState* irs)
3784 irs->doLineNote(loc);
3785 irs->continueLoop(ident);
3788 void
3789 BreakStatement::toIR(IRState* irs)
3791 irs->doLineNote(loc);
3792 irs->exitLoop(ident);
3795 void
3796 ReturnStatement::toIR(IRState* irs)
3798 irs->doLineNote(loc);
3800 if (exp) {
3801 if (exp->type->toBasetype()->ty != Tvoid) { // %% == Type::tvoid ?
3802 FuncDeclaration * func = irs->func;
3803 Type * ret_type = func->tintro ?
3804 func->tintro->nextOf() : func->type->nextOf();
3806 if (func->isMain() && ret_type->toBasetype()->ty == Tvoid)
3807 ret_type = Type::tint32;
3809 tree result_decl = DECL_RESULT( irs->func->toSymbol()->Stree );
3810 tree result_assign = build ( MODIFY_EXPR,
3811 TREE_TYPE( result_decl ), result_decl,
3812 // %% convert for init -- if we were returning a reference,
3813 // would want to take the address...
3814 irs->convertForAssignment(exp, (Type*)ret_type) );
3816 irs->doReturn(result_assign); // expand_return(result_assign);
3817 } else {
3818 //irs->doExp(exp);
3819 irs->doReturn(NULL_TREE);
3821 } else {
3822 irs->doReturn(NULL_TREE);
3826 void
3827 DefaultStatement::toIR(IRState * irs)
3829 irs->doCase(NULL_TREE, cblock);
3830 if (statement)
3831 statement->toIR( irs );
3834 void
3835 CaseStatement::toIR(IRState * irs)
3837 tree case_value;
3839 if ( exp->type->isscalar() )
3840 case_value = exp->toElem(irs);
3841 else
3842 case_value = irs->integerConstant(index, Type::tint32);
3843 irs->doCase(case_value, cblock);
3844 if (statement)
3845 statement->toIR( irs );
3848 void
3849 SwitchStatement::toIR(IRState * irs)
3851 tree cond_tree;
3852 // %% also what about c-semantics doing emit_nop() ?
3853 irs->doLineNote( loc );
3855 cond_tree = condition->toElem( irs );
3857 Type * cond_type = condition->type->toBasetype();
3858 if (cond_type->ty == Tarray) {
3859 Type * elem_type = cond_type->nextOf()->toBasetype();
3860 LibCall lib_call;
3861 switch (elem_type->ty) {
3862 case Tchar: lib_call = LIBCALL_SWITCH_STRING; break;
3863 case Twchar: lib_call = LIBCALL_SWITCH_USTRING; break;
3864 case Tdchar: lib_call = LIBCALL_SWITCH_DSTRING; break;
3865 default:
3866 ::error("switch statement value must be an array of some character type, not %s", elem_type->toChars());
3867 abort();
3870 // Apparently the backend is supposed to sort and set the indexes
3871 // on the case array
3872 // have to change them to be useable
3873 cases->sort(); // %%!!
3875 Symbol * s = static_sym();
3876 dt_t ** pdt = & s->Sdt;
3877 s->Sseg = CDATA;
3878 for (unsigned case_i = 0; case_i < cases->dim; case_i++) {
3879 CaseStatement * case_stmt = (CaseStatement *) cases->data[case_i];
3880 pdt = case_stmt->exp->toDt( pdt );
3881 case_stmt->index = case_i;
3883 outdata(s);
3884 tree p_table = irs->addressOf(s->Stree);
3886 tree args[2] = {
3887 irs->darrayVal(cond_type->arrayOf()->toCtype(), cases->dim,
3888 p_table),
3889 cond_tree };
3891 cond_tree = irs->libCall(lib_call, 2, args);
3892 } else if (! cond_type->isscalar()) {
3893 ::error("cannot handle switch condition of type %s", cond_type->toChars());
3894 abort();
3897 // Build LABEL_DECLs now so they can be refered to by goto case
3898 if (cases) {
3899 for (unsigned i = 0; i < cases->dim; i++) {
3900 CaseStatement * case_stmt = (CaseStatement *) cases->data[i];
3901 case_stmt->cblock = irs->label(case_stmt->loc); //make_case_label(case_stmt->loc);
3903 if (sdefault)
3904 sdefault->cblock = irs->label(sdefault->loc); //make_case_label(sdefault->loc);
3907 cond_tree = fold(cond_tree);
3908 irs->startCase(this, cond_tree);
3909 if (body)
3910 body->toIR( irs );
3911 irs->endCase(cond_tree);
3915 void
3916 Statement::toIR(IRState*)
3918 ::error("Statement::toIR: don't know what to do (%s)", toChars());
3919 abort();
3922 void
3923 IfStatement::toIR(IRState * irs)
3925 if (match) {
3926 irs->startScope();
3927 irs->emitLocalVar(match);
3929 irs->startCond(this, condition);
3930 if (ifbody)
3931 ifbody->toIR( irs );
3932 if ( elsebody ) {
3933 irs->startElse();
3934 elsebody->toIR ( irs );
3936 irs->endCond();
3937 if (match)
3938 irs->endScope();
3941 void
3942 ForeachStatement::toIR(IRState* irs)
3944 // %% better?: set iter to start - 1 and use result of increment for condition?
3946 // side effects?
3948 Type * agg_type = aggr->type->toBasetype();
3949 Type * elem_type = agg_type->nextOf()->toBasetype();
3950 tree iter_decl;
3951 tree bound_expr;
3952 tree iter_init_expr;
3953 tree aggr_expr = irs->maybeMakeTemp( aggr->toElem(irs) );
3955 assert(value);
3957 gcc_assert(elem_type->ty != Tbit);
3959 irs->startScope();
3960 irs->startBindings(); /* Variables created by the function will probably
3961 end up in a contour created by emitLocalVar. This
3962 startBindings call is just to be safe */
3963 irs->doLineNote( loc );
3965 Loc default_loc;
3966 if (loc.filename)
3967 default_loc = loc;
3968 else {
3969 fprintf(stderr, "EXPER: I need this\n");
3970 default_loc = Loc(g.mod, 1); // %% fix
3973 if (! value->loc.filename)
3974 g.ofile->setDeclLoc( value->toSymbol()->Stree, default_loc );
3976 irs->emitLocalVar(value, true);
3978 if (key) {
3979 if (! key->loc.filename)
3980 g.ofile->setDeclLoc( key->toSymbol()->Stree, default_loc );
3981 if (! key->init)
3982 DECL_INITIAL( key->toSymbol()->Stree ) = op == TOKforeach ?
3983 irs->integerConstant(0, key->type) :
3984 irs->arrayLength(aggr_expr, agg_type);
3986 irs->emitLocalVar(key); // %% getExpInitializer causes uneeded initialization
3989 bool iter_is_value;
3990 if (value->isRef() || value->isOut()) {
3991 iter_is_value = true;
3992 iter_decl = irs->var(value);
3993 } else {
3994 iter_is_value = false;
3995 iter_decl = irs->localVar(elem_type->pointerTo());
3996 irs->expandDecl(iter_decl);
3999 if ( agg_type->ty == Tsarray) {
4000 bound_expr = ((TypeSArray *) agg_type)->dim->toElem(irs);
4001 iter_init_expr = irs->addressOf( aggr_expr );
4002 // Type needs to be pointer-to-element to get pointerIntSum
4003 // to work
4004 iter_init_expr = irs->nop(iter_init_expr,
4005 agg_type->nextOf()->pointerTo()->toCtype());
4006 } else {
4007 bound_expr = irs->darrayLenRef( aggr_expr );
4008 iter_init_expr = irs->darrayPtrRef( aggr_expr );
4010 iter_init_expr = save_expr( iter_init_expr );
4011 bound_expr = irs->pointerIntSum(iter_init_expr, bound_expr);
4012 // aggr. isn't supposed to be modified, so...
4013 bound_expr = save_expr( bound_expr );
4015 enum tree_code iter_op = PLUS_EXPR;
4017 if (op == TOKforeach_reverse)
4019 tree t = iter_init_expr;
4020 iter_init_expr = bound_expr;
4021 bound_expr = t;
4023 iter_op = MINUS_EXPR;
4026 tree condition = build(NE_EXPR, boolean_type_node, iter_decl, bound_expr);
4027 tree incr_expr =
4028 build(MODIFY_EXPR, void_type_node, iter_decl,
4029 build(iter_op, TREE_TYPE(iter_decl), iter_decl,
4030 size_int(elem_type->size())));
4031 if (key) {
4032 tree key_decl = irs->var(key);
4033 tree key_incr_expr =
4034 build(MODIFY_EXPR, void_type_node, key_decl,
4035 build(iter_op, TREE_TYPE(key_decl), key_decl,
4036 irs->integerConstant(1, TREE_TYPE(key_decl))));
4037 incr_expr = irs->compound(incr_expr, key_incr_expr);
4040 irs->doExp( build(MODIFY_EXPR, void_type_node, iter_decl, iter_init_expr) );
4042 irs->startLoop(this);
4043 irs->exitIfFalse(condition);
4044 if ( op == TOKforeach_reverse )
4045 irs->doExp( incr_expr );
4046 if ( ! iter_is_value )
4047 irs->doExp( build(MODIFY_EXPR, void_type_node, irs->var(value),
4048 irs->indirect(iter_decl)) );
4049 if (body)
4050 body->toIR( irs );
4051 irs->continueHere();
4053 if ( op == TOKforeach )
4054 irs->doExp( incr_expr );
4056 irs->endLoop();
4058 irs->endBindings(); // not really needed
4059 irs->endScope();
4062 #if V2
4064 void
4065 ForeachRangeStatement::toIR(IRState * irs)
4067 bool fwd = op == TOKforeach;
4069 irs->startScope();
4070 irs->startBindings(); /* Variables created by the function will probably
4071 end up in a contour created by emitLocalVar. This
4072 startBindings call is just to be safe */
4073 irs->doLineNote( loc );
4075 gcc_assert(key != NULL);
4076 gcc_assert(lwr != NULL);
4077 gcc_assert(upr != NULL);
4079 // Front end ensures no storage class
4080 irs->emitLocalVar(key, true);
4081 tree key_decl = irs->var(key);
4082 tree lwr_decl = irs->localVar(lwr->type);
4083 tree upr_decl = irs->localVar(upr->type);
4084 tree iter_expr = irs->vmodify(key_decl,
4085 build2(fwd ? PLUS_EXPR : MINUS_EXPR, TREE_TYPE(key_decl),
4086 key_decl, irs->integerConstant(1, TREE_TYPE(key_decl))));
4087 tree condition;
4089 irs->expandDecl(lwr_decl);
4090 irs->expandDecl(upr_decl);
4091 irs->doExp( irs->vmodify(lwr_decl, lwr->toElem(irs)) );
4092 irs->doExp( irs->vmodify(upr_decl, upr->toElem(irs)) );
4094 condition = build2(fwd ? LT_EXPR : GT_EXPR, boolean_type_node,
4095 key_decl, fwd ? upr_decl : lwr_decl);
4097 irs->doExp( irs->vmodify(key_decl, fwd ? lwr_decl : upr_decl) );
4099 irs->startLoop(this);
4100 if (! fwd)
4101 irs->continueHere();
4102 irs->exitIfFalse(condition);
4103 if (! fwd)
4104 irs->doExp(iter_expr);
4105 if (body)
4106 body->toIR( irs );
4107 if ( fwd ) {
4108 irs->continueHere();
4109 irs->doExp(iter_expr);
4111 irs->endLoop();
4113 irs->endBindings(); // not really needed
4114 irs->endScope();
4117 #endif
4119 void
4120 ForStatement::toIR(IRState * irs)
4122 irs->doLineNote(loc);
4123 // %% scope
4124 if (init)
4125 init->toIR( irs );
4126 irs->startLoop(this);
4127 if (condition)
4128 irs->exitIfFalse(condition);
4129 if (body)
4130 body->toIR( irs );
4131 irs->continueHere();
4132 if (increment)
4133 irs->doExp(increment->toElem(irs)); // force side effects?
4134 irs->endLoop();
4137 void
4138 DoStatement::toIR(IRState * irs)
4140 irs->doLineNote(loc);
4141 irs->startLoop(this);
4142 if (body)
4143 body->toIR( irs );
4144 irs->continueHere();
4145 irs->exitIfFalse(condition);
4146 irs->endLoop();
4149 void
4150 WhileStatement::toIR(IRState* irs)
4152 irs->doLineNote(loc); // store for next statement...
4153 irs->startLoop(this);
4154 irs->continueHere();
4155 irs->exitIfFalse(condition, 1); // 1 == is topcond .. good as deprecated..
4156 if (body)
4157 body->toIR( irs );
4158 irs->endLoop();
4161 void
4162 ScopeStatement::toIR(IRState* irs)
4164 if (statement) {
4165 irs->startScope();
4166 statement->toIR( irs );
4167 irs->endScope();
4171 void
4172 CompoundStatement::toIR(IRState* irs)
4174 if (statements) {
4175 for (unsigned i = 0; i < statements->dim; i++) {
4176 Statement * statement = (Statement *) statements->data[i];
4178 if (statement)
4179 statement->toIR(irs);
4184 void
4185 UnrolledLoopStatement::toIR(IRState* irs)
4187 if (statements) {
4188 irs->startLoop(this);
4189 irs->continueHere();
4190 for (unsigned i = 0; i < statements->dim; i++) {
4191 Statement * statement = (Statement *) statements->data[i];
4193 if (statement)
4195 irs->setContinueLabel( irs->label(loc) );
4196 statement->toIR(irs);
4197 irs->continueHere();
4200 irs->exitLoop(NULL);
4201 irs->endLoop();
4205 void
4206 ExpStatement::toIR(IRState * irs)
4208 if (exp) {
4209 gen.doLineNote(loc);
4211 tree exp_tree = exp->toElem(irs);
4213 irs->doExp(exp_tree);
4214 } else {
4215 // nothing
4219 #if V2
4220 void
4221 PragmaStatement::toIR(IRState *)
4223 // nothing
4225 #endif
4227 void
4228 EnumDeclaration::toDebug()
4234 Dsymbol::cvMember(unsigned char*)
4236 return 0;
4239 EnumDeclaration::cvMember(unsigned char*)
4241 return 0;
4244 FuncDeclaration::cvMember(unsigned char*)
4246 return 0;
4249 VarDeclaration::cvMember(unsigned char*)
4251 return 0;
4254 TypedefDeclaration::cvMember(unsigned char*)
4256 return 0;
4259 #if D_GCC_VER < 40
4262 d_expand_expr(tree exp, rtx target , enum machine_mode tmode, int modifier, rtx *)
4264 if ( TREE_CODE(exp) == (enum tree_code) D_STMT_EXPR ) {
4265 IRState * irs;
4266 Statement * stmt;
4268 gen.retrieveStmtExpr(exp, & stmt, & irs);
4269 // need push_temp_slots()?
4271 tree rtl_expr = expand_start_stmt_expr(1);
4272 // This startBindings call is needed so get_last_insn() doesn't return NULL
4273 // in expand_start_case().
4274 irs->startBindings();
4275 // preserve_temp_slots as in c-common.c:c_expand_expr
4277 stmt->toIR(irs);
4278 irs->endBindings();
4280 expand_end_stmt_expr (rtl_expr);
4282 rtx result = expand_expr (rtl_expr, target, tmode, (enum expand_modifier) modifier);
4283 pop_temp_slots();
4284 return result;
4285 } else if ( TREE_CODE(exp) == (enum tree_code) D_ARRAY_SET_EXPR ){
4286 // %% if single byte element, expand to memset
4288 assert( POINTER_TYPE_P( TREE_TYPE( TREE_OPERAND( exp, 0 ))));
4289 assert( INTEGRAL_TYPE_P( TREE_TYPE( TREE_OPERAND( exp, 2 ))));
4290 // assuming unsigned source is unsigned
4292 push_temp_slots (); // will this work? maybe expand_start_binding
4293 tree rtl_expr = expand_start_stmt_expr(1);
4295 do_array_set(g.irs, // %% fix!
4296 TREE_OPERAND(exp, 0), TREE_OPERAND(exp, 1), TREE_OPERAND(exp, 2));
4298 expand_end_stmt_expr(rtl_expr);
4299 rtx result = expand_expr(rtl_expr, target, tmode, (enum expand_modifier) modifier);
4300 pop_temp_slots ();
4301 return result;
4302 } else {
4303 abort();
4307 #endif
4308 /*else..
4309 void x(tree ptr, tree src, tree count) {
4310 tree count_var =;
4311 tree ptr_var = ;
4312 build(BIND_EXPR, count_var, t_loop, block???0
4316 static tree
4317 d_build_eh_type_type(tree type)
4319 TypeClass * d_type = (TypeClass *) IRState::getDType(type);
4320 assert(d_type);
4321 d_type = (TypeClass *) d_type->toBasetype();
4322 assert(d_type->ty == Tclass);
4323 return IRState::addressOf( d_type->sym->toSymbol()->Stree );
4326 tree d_void_zero_node;
4328 tree d_null_pointer;
4329 tree d_vtbl_ptr_type_node;
4331 void
4332 gcc_d_backend_init()
4334 // %% need this here to add the type decls ...
4335 init_global_binding_level();
4337 // This allows the code in d-builtins2 to not have to worry about
4338 // converting (C signed char *) to (D char *) for string arguments of
4339 // built-in functions.
4340 flag_signed_char = 0;
4341 // This is required or we'll crash pretty early on. %%log
4342 build_common_tree_nodes (flag_signed_char
4343 #if D_GCC_VER >= 40
4344 , false
4345 #endif
4348 // This is also required (or the manual equivalent) or crashes
4349 // will occur later
4350 size_type_node = d_type_for_mode(ptr_mode, 1);
4352 // c was: TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
4353 //signed_size_type_node = c_common_signed_type (size_type_node);
4355 // If this is called after the next statements, you'll get an ICE.
4356 set_sizetype(size_type_node);
4359 // need this for void.. %% but this crashes... probably need to impl
4360 // some things in dc-lang.cc
4361 build_common_tree_nodes_2 (0 /* %% support the option */);
4363 // Specific to D (but so far all taken from C)
4364 #if D_GCC_VER < 40
4365 d_void_zero_node = build_int_2 (0, 0);
4366 TREE_TYPE (d_void_zero_node) = void_type_node;
4367 #else
4368 d_void_zero_node = build_int_cst (void_type_node, 0);
4369 #endif
4370 // %%TODO: we are relying on default boolean_type_node being 8bit / same as Tbit
4372 d_null_pointer = convert(ptr_type_node, integer_zero_node);
4374 TYPE_NAME( integer_type_node ) = build_decl(TYPE_DECL, get_identifier("int"), integer_type_node);
4375 TYPE_NAME( char_type_node ) = build_decl(TYPE_DECL, get_identifier("cchar"), char_type_node); // "char?"
4377 REALSIZE = int_size_in_bytes(long_double_type_node);
4378 REALPAD = 0;
4379 PTRSIZE = int_size_in_bytes(ptr_type_node);
4380 switch (int_size_in_bytes(size_type_node)) {
4381 case 4:
4382 Tsize_t = Tuns32;
4383 Tindex = Tint32;
4384 break;
4385 case 8:
4386 Tsize_t = Tuns64;
4387 Tindex = Tint64;
4388 break;
4389 default:
4390 abort();
4392 switch ( PTRSIZE ) {
4393 case 4:
4394 assert(POINTER_SIZE == 32);
4395 Tptrdiff_t = Tint32;
4396 break;
4397 case 8:
4398 assert(POINTER_SIZE == 64);
4399 Tptrdiff_t = Tint64;
4400 break;
4401 default:
4402 abort();
4404 #if V2
4405 CLASSINFO_SIZE = 19 * PTRSIZE;
4406 #else
4407 CLASSINFO_SIZE = 18 * PTRSIZE;
4408 #endif
4410 d_init_builtins();
4412 if (flag_exceptions) {
4413 eh_personality_libfunc = init_one_libfunc(d_using_sjlj_exceptions()
4414 ? "__gdc_personality_sj0" : "__gdc_personality_v0");
4415 #if D_GCC_VER >= 41
4416 default_init_unwind_resume_libfunc ();
4417 #endif
4418 lang_eh_runtime_type = d_build_eh_type_type;
4419 using_eh_for_cleanups ();
4420 // lang_proctect_cleanup_actions = ...; // no need? ... probably needed for autos
4423 /* copied and modified from cp/decl.c; only way for vtable to work in gdb... */
4424 // or not, I'm feeling very confused...
4425 if (1) {
4426 /* Make sure we get a unique function type, so we can give
4427 its pointer type a name. (This wins for gdb.) */
4428 tree vfunc_type = make_node (FUNCTION_TYPE);
4429 TREE_TYPE (vfunc_type) = Type::tint32->toCtype(); // integer_type_node; messed up built in types?
4430 TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
4431 layout_type (vfunc_type);
4433 tree vtable_entry_type = build_pointer_type (vfunc_type);
4434 d_vtbl_ptr_type_node = build_pointer_type(vtable_entry_type);
4435 layout_type (d_vtbl_ptr_type_node);// %%TODO: check if needed
4438 // This also allows virtual functions to be called, but when vtbl entries,
4439 // are inspected, function symbol names do not appear.
4440 // d_vtbl_ptr_type_node = Type::tvoid->pointerTo()->pointerTo()->toCtype();
4442 // This is the C main, not the D main
4443 main_identifier_node = get_identifier ("main");
4446 void
4447 gcc_d_backend_term()