2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* Code to help convert to the intermediate representation
12 * of the compiler back end.
21 #include "expression.h"
24 #include "declaration.h"
26 #include "aggregate.h"
33 #include "..\tk\mem.h" // for mem_malloc
35 #include "../tk/mem.h" // for mem_malloc
50 static char __file__
[] = __FILE__
; /* for tassert.h */
53 /*********************************************
54 * Produce elem which increments the usage count for a particular line.
55 * Used to implement -cov switch (coverage analysis).
58 elem
*incUsageElem(IRState
*irs
, Loc loc
)
60 unsigned linnum
= loc
.linnum
;
62 if (!irs
->blx
->module
->cov
|| !linnum
||
63 loc
.filename
!= irs
->blx
->module
->srcfile
->toChars())
66 //printf("cov = %p, covb = %p, linnum = %u\n", irs->blx->module->cov, irs->blx->module->covb, p, linnum);
68 linnum
--; // from 1-based to 0-based
70 /* Set bit in covb[] indicating this is a valid code line number
72 unsigned *p
= irs
->blx
->module
->covb
;
73 if (p
) // covb can be NULL if it has already been written out to its .obj file
75 p
+= linnum
/ (sizeof(*p
) * 8);
76 *p
|= 1 << (linnum
& (sizeof(*p
) * 8 - 1));
80 e
= el_ptr(irs
->blx
->module
->cov
);
81 e
= el_bin(OPadd
, TYnptr
, e
, el_long(TYuint
, linnum
* 4));
82 e
= el_una(OPind
, TYuint
, e
);
83 e
= el_bin(OPaddass
, TYuint
, e
, el_long(TYuint
, 1));
87 /******************************************
88 * Return elem that evaluates to the static frame pointer for function fd.
89 * If fd is a member function, the returned expression will compute the value
90 * of fd's 'this' variable.
91 * This routine is critical for implementing nested functions.
94 elem
*getEthis(Loc loc
, IRState
*irs
, Dsymbol
*fd
)
97 FuncDeclaration
*thisfd
= irs
->getFunc();
98 Dsymbol
*fdparent
= fd
->toParent2();
100 //printf("getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", thisfd->toChars(), fd->toChars(), fdparent->toChars());
101 if (fdparent
== thisfd
)
102 { /* Going down one nesting level, i.e. we're calling
103 * a nested function from its enclosing function.
107 ethis
= el_var(irs
->sclosure
);
111 { // We have a 'this' pointer for the current function
112 ethis
= el_var(irs
->sthis
);
114 /* If no variables in the current function's frame are
115 * referenced by nested functions, then we can 'skip'
116 * adding this frame into the linked list of stack
120 if (thisfd
->closureVars
.dim
)
122 if (thisfd
->nestedFrameRef
)
124 { /* Local variables are referenced, can't skip.
125 * Address of 'this' gives the 'this' for the nested
128 ethis
= el_una(OPaddr
, TYnptr
, ethis
);
132 { /* No 'this' pointer for current function,
133 * use NULL if no references to the current function's frame
135 ethis
= el_long(TYnptr
, 0);
137 if (thisfd
->closureVars
.dim
)
139 if (thisfd
->nestedFrameRef
)
141 { /* OPframeptr is an operator that gets the frame pointer
142 * for the current function, i.e. for the x86 it gets
145 ethis
->Eoper
= OPframeptr
;
151 if (!irs
->sthis
) // if no frame pointer for this function
153 fd
->error(loc
, "is a nested function and cannot be accessed from %s", irs
->getFunc()->toChars());
154 ethis
= el_long(TYnptr
, 0); // error recovery
158 ethis
= el_var(irs
->sthis
);
161 { /* Go up a nesting level, i.e. we need to find the 'this'
162 * of an enclosing function.
163 * Our 'enclosing function' may also be an inner class.
166 //printf("\ts = '%s'\n", s->toChars());
167 thisfd
= s
->isFuncDeclaration();
169 { /* Enclosing function is a function.
171 if (fdparent
== s
->toParent2())
173 if (thisfd
->isNested())
175 FuncDeclaration
*p
= s
->toParent2()->isFuncDeclaration();
177 if (!p
|| p
->closureVars
.dim
)
179 if (!p
|| p
->nestedFrameRef
)
181 ethis
= el_una(OPind
, TYnptr
, ethis
);
183 else if (thisfd
->vthis
)
190 { /* Enclosed by a class. That means the current
191 * function must be a member function of that class.
193 ClassDeclaration
*cd
= s
->isClassDeclaration();
196 if (//cd->baseClass == fd ||
197 fd
->isClassDeclaration() &&
198 fd
->isClassDeclaration()->isBaseOf(cd
, NULL
))
200 if (!cd
->isNested() || !cd
->vthis
)
203 irs
->getFunc()->error(loc
, "cannot get frame pointer to %s", fd
->toChars());
204 return el_long(TYnptr
, 0); // error recovery
206 ethis
= el_bin(OPadd
, TYnptr
, ethis
, el_long(TYint
, cd
->vthis
->offset
));
207 ethis
= el_una(OPind
, TYnptr
, ethis
);
208 if (fdparent
== s
->toParent2())
210 if (fd
== s
->toParent2())
212 /* Remember that frames for functions that have no
213 * nested references are skipped in the linked list
217 if (s
->toParent2()->isFuncDeclaration()->closureVars
.dim
)
219 if (s
->toParent2()->isFuncDeclaration()->nestedFrameRef
)
221 ethis
= el_una(OPind
, TYnptr
, ethis
);
224 if (s
->toParent2()->isFuncDeclaration())
226 /* Remember that frames for functions that have no
227 * nested references are skipped in the linked list
231 if (s
->toParent2()->isFuncDeclaration()->closureVars
.dim
)
233 if (s
->toParent2()->isFuncDeclaration()->nestedFrameRef
)
235 ethis
= el_una(OPind
, TYnptr
, ethis
);
252 /*******************************************
253 * Convert intrinsic function to operator.
254 * Returns that operator, -1 if not an intrinsic function.
257 int intrinsic_op(char *name
)
259 static const char *namearray
[] =
271 "9intrinsic2btFxPkkZi",
272 "9intrinsic3bsfFkZi",
273 "9intrinsic3bsrFkZi",
274 "9intrinsic3btcFPkkZi",
275 "9intrinsic3btrFPkkZi",
276 "9intrinsic3btsFPkkZi",
277 "9intrinsic3inpFkZh",
278 "9intrinsic4inplFkZk",
279 "9intrinsic4inpwFkZt",
280 "9intrinsic4outpFkhZh",
281 "9intrinsic5bswapFkZk",
282 "9intrinsic5outplFkkZk",
283 "9intrinsic5outpwFktZt",
285 static unsigned char ioptab
[] =
316 assert(sizeof(namearray
) / sizeof(char *) == sizeof(ioptab
));
317 for (i
= 0; i
< sizeof(namearray
) / sizeof(char *) - 1; i
++)
319 if (strcmp(namearray
[i
], namearray
[i
+ 1]) >= 0)
321 printf("namearray[%d] = '%s'\n", i
, namearray
[i
]);
327 length
= strlen(name
);
328 if (length
< 11 || memcmp(name
, "_D3std", 6) != 0)
331 i
= binary(name
+ 6, namearray
, sizeof(namearray
) / sizeof(char *));
332 return (i
== -1) ? i
: ioptab
[i
];
336 /**************************************
337 * Given an expression e that is an array,
338 * determine and set the 'length' variable.
340 * lengthVar Symbol of 'length' variable
341 * &e expression that is the array
342 * t1 Type of the array
344 * e is rewritten to avoid side effects
346 * expression that initializes 'length'
349 elem
*resolveLengthVar(VarDeclaration
*lengthVar
, elem
**pe
, Type
*t1
)
351 //printf("resolveLengthVar()\n");
354 if (lengthVar
&& !(lengthVar
->storage_class
& STCconst
))
358 if (t1
->ty
== Tsarray
)
359 { TypeSArray
*tsa
= (TypeSArray
*)t1
;
360 integer_t length
= tsa
->dim
->toInteger();
362 elength
= el_long(TYuint
, length
);
365 else if (t1
->ty
== Tarray
)
368 *pe
= el_same(&elength
);
369 elength
= el_una(OP64_32
, TYuint
, elength
);
372 slength
= lengthVar
->toSymbol();
373 //symbol_add(slength);
375 einit
= el_bin(OPeq
, TYuint
, el_var(slength
), elength
);
381 /*************************************
382 * Closures are implemented by taking the local variables that
383 * need to survive the scope of the function, and copying them
384 * into a gc allocated chuck of memory. That chunk, called the
385 * closure here, is inserted into the linked list of stack
386 * frames instead of the usual stack frame.
388 * buildClosure() inserts code just after the function prolog
389 * is complete. It allocates memory for the closure, allocates
390 * a local variable (sclosure) to point to it, inserts into it
391 * the link to the enclosing frame, and copies into it the parameters
392 * that are referred to in nested functions.
393 * In VarExp::toElem and SymOffExp::toElem, when referring to a
394 * variable that is in a closure, takes the offset from sclosure rather
395 * than from the frame pointer.
397 * getEthis() and NewExp::toElem need to use sclosure, if set, rather
398 * than the current frame pointer.
403 void FuncDeclaration::buildClosure(IRState
*irs
)
406 { // Generate closure on the heap
407 // BUG: doesn't capture variadic arguments passed to this function
409 /* BUG: doesn't handle destructors for the local variables.
410 * The way to do it is to make the closure variables the fields
417 * ... closure variables ...
418 * ~this() { call destructor }
422 //printf("FuncDeclaration::buildClosure()\n");
424 sclosure
= symbol_name("__closptr",SCauto
,Type::tvoidptr
->toCtype());
425 sclosure
->Sflags
|= SFLtrue
| SFLfree
;
426 symbol_add(sclosure
);
427 irs
->sclosure
= sclosure
;
429 unsigned offset
= PTRSIZE
; // leave room for previous sthis
430 for (int i
= 0; i
< closureVars
.dim
; i
++)
431 { VarDeclaration
*v
= (VarDeclaration
*)closureVars
.data
[i
];
432 assert(v
->isVarDeclaration());
434 if (v
->needsAutoDtor())
435 v
->error("has scoped destruction, cannot build closure");
437 /* Align and allocate space for v in the closure
438 * just like AggregateDeclaration::addField() does.
440 unsigned memsize
= v
->type
->size();
441 unsigned memalignsize
= v
->type
->alignsize();
442 unsigned xalign
= v
->type
->memalign(global
.structalign
);
443 AggregateDeclaration::alignmember(xalign
, memalignsize
, &offset
);
447 /* Can't do nrvo if the variable is put in a closure, since
448 * what the shidden points to may no longer exist.
450 if (nrvo_can
&& nrvo_var
== v
)
455 // offset is now the size of the closure
457 // Allocate memory for the closure
459 e
= el_long(TYint
, offset
);
460 e
= el_bin(OPcall
, TYnptr
, el_var(rtlsym
[RTLSYM_ALLOCMEMORY
]), e
);
462 // Assign block of memory to sclosure
463 // sclosure = allocmemory(sz);
464 e
= el_bin(OPeq
, TYvoid
, el_var(sclosure
), e
);
466 // Set the first element to sthis
467 // *(sclosure + 0) = sthis;
470 ethis
= el_var(irs
->sthis
);
472 ethis
= el_long(TYnptr
, 0);
473 elem
*ex
= el_una(OPind
, TYnptr
, el_var(sclosure
));
474 ex
= el_bin(OPeq
, TYnptr
, ex
, ethis
);
475 e
= el_combine(e
, ex
);
477 // Copy function parameters into closure
478 for (int i
= 0; i
< closureVars
.dim
; i
++)
479 { VarDeclaration
*v
= (VarDeclaration
*)closureVars
.data
[i
];
481 if (!v
->isParameter())
483 tym_t tym
= v
->type
->totym();
484 if (v
->type
->toBasetype()->ty
== Tsarray
|| v
->isOut() || v
->isRef())
485 tym
= TYnptr
; // reference parameters are just pointers
486 ex
= el_bin(OPadd
, TYnptr
, el_var(sclosure
), el_long(TYint
, v
->offset
));
487 ex
= el_una(OPind
, tym
, ex
);
488 if (ex
->Ety
== TYstruct
)
489 { ex
->Enumbytes
= v
->type
->size();
490 ex
= el_bin(OPstreq
, tym
, ex
, el_var(v
->toSymbol()));
491 ex
->Enumbytes
= v
->type
->size();
494 ex
= el_bin(OPeq
, tym
, ex
, el_var(v
->toSymbol()));
496 e
= el_combine(e
, ex
);
499 block_appendexp(irs
->blx
->curblock
, e
);