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 "9intrinsic2btFPkkZi",
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
410 sclosure
= symbol_name("__closptr",SCauto
,Type::tvoidptr
->toCtype());
411 sclosure
->Sflags
|= SFLtrue
| SFLfree
;
412 symbol_add(sclosure
);
413 irs
->sclosure
= sclosure
;
415 unsigned offset
= PTRSIZE
; // leave room for previous sthis
416 for (int i
= 0; i
< closureVars
.dim
; i
++)
417 { VarDeclaration
*v
= (VarDeclaration
*)closureVars
.data
[i
];
418 assert(v
->isVarDeclaration());
420 /* Align and allocate space for v in the closure
421 * just like AggregateDeclaration::addField() does.
423 unsigned memsize
= v
->type
->size();
424 unsigned memalignsize
= v
->type
->alignsize();
425 unsigned xalign
= v
->type
->memalign(global
.structalign
);
426 AggregateDeclaration::alignmember(xalign
, memalignsize
, &offset
);
430 /* Can't do nrvo if the variable is put in a closure, since
431 * what the shidden points to may no longer exist.
433 if (nrvo_can
&& nrvo_var
== v
)
438 // offset is now the size of the closure
440 // Allocate memory for the closure
442 e
= el_long(TYint
, offset
);
443 e
= el_bin(OPcall
, TYnptr
, el_var(rtlsym
[RTLSYM_ALLOCMEMORY
]), e
);
445 // Assign block of memory to sclosure
446 // sclosure = allocmemory(sz);
447 e
= el_bin(OPeq
, TYvoid
, el_var(sclosure
), e
);
449 // Set the first element to sthis
450 // *(sclosure + 0) = sthis;
453 ethis
= el_var(irs
->sthis
);
455 ethis
= el_long(TYnptr
, 0);
456 elem
*ex
= el_una(OPind
, TYnptr
, el_var(sclosure
));
457 ex
= el_bin(OPeq
, TYnptr
, ex
, ethis
);
458 e
= el_combine(e
, ex
);
460 // Copy function parameters into closure
461 for (int i
= 0; i
< closureVars
.dim
; i
++)
462 { VarDeclaration
*v
= (VarDeclaration
*)closureVars
.data
[i
];
464 if (!v
->isParameter())
466 tym_t tym
= v
->type
->totym();
467 if (v
->type
->toBasetype()->ty
== Tsarray
|| v
->isOut() || v
->isRef())
468 tym
= TYnptr
; // reference parameters are just pointers
469 ex
= el_bin(OPadd
, TYnptr
, el_var(sclosure
), el_long(TYint
, v
->offset
));
470 ex
= el_una(OPind
, tym
, ex
);
471 if (ex
->Ety
== TYstruct
)
472 { ex
->Enumbytes
= v
->type
->size();
473 ex
= el_bin(OPstreq
, tym
, ex
, el_var(v
->toSymbol()));
474 ex
->Enumbytes
= v
->type
->size();
477 ex
= el_bin(OPeq
, tym
, ex
, el_var(v
->toSymbol()));
479 e
= el_combine(e
, ex
);
482 block_appendexp(irs
->blx
->curblock
, e
);