Allow returning something of type void in a function that returns void
[delight/core.git] / d-irstate.cc
blob9438b4455eea2a82473161160db8cbd95fdea703
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"
20 #include "d-lang.h"
21 #include "d-irstate.h"
23 #include <assert.h>
25 #include "total.h"
26 #include "init.h"
27 #include "symbol.h"
29 #include "d-codegen.h"
32 Array IRBase::deferredFuncDecls;
34 IRBase::IRBase()
36 parent = 0;
37 func = 0;
38 volatileDepth = 0;
40 // declContextStack is composed... choose one..
41 #if D_GCC_VER >= 40
42 statementList = NULL_TREE;
43 #endif
46 IRState *
47 IRBase::startFunction(FuncDeclaration * decl)
49 IRState * new_irs = new IRState();
50 new_irs->parent = g.irs;
51 new_irs->func = decl;
53 tree decl_tree = decl->toSymbol()->Stree;
55 // %%MOVE to ofile -- shuold be able to do after codegen
56 // Need to do this for GCC 3.4 or functions will not be emitted
57 d_add_global_function( decl_tree );
59 g.irs = (IRState*) new_irs;
61 ModuleInfo & mi = * g.mi();
62 if (decl->isStaticConstructor())
63 mi.ctors.push(decl);
64 else if (decl->isStaticDestructor())
65 mi.dtors.push(decl);
66 else if (decl->isUnitTestDeclaration())
67 mi.unitTests.push(decl);
69 return new_irs;
72 void
73 IRBase::endFunction()
75 assert(scopes.dim == 0);
77 func = 0; // make shouldDeferFunction return false
78 // Assumes deferredFuncDecls will not change after this point
80 g.irs = (IRState *) parent;
82 if (g.irs == & gen) {
83 Array a;
84 a.append(& deferredFuncDecls);
85 deferredFuncDecls.setDim(0);
86 for (unsigned i = 0; i < a.dim; i++) {
87 FuncDeclaration * f = (FuncDeclaration *) a.data[i];
88 f->toObjFile(false);
92 // %%TODO
94 if (can_delete)
95 delete this;
99 bool
100 IRBase::shouldDeferFunction(FuncDeclaration * decl)
102 #if D_GCC_VER < 40
103 if (! func || gen.functionNeedsChain(decl)) {
104 return false;
105 } else {
106 deferredFuncDecls.push(decl);
107 return true;
109 #else
110 /* There is no need to defer functions for 4.0. In fact, deferring
111 causes problems because statically nested functions need to
112 be prepared (maybe just have a struct function allocated) before
113 the nesting function goes though lower_nested_functions.
115 Start nesting function F.
116 Defer nested function (a static class method)
117 Output class's virtual table
118 The reference to the function for the vtable creates a cgraph node
120 lower_nested(F)
121 the method is in the nested cgraph nodes, but the function hasing
122 even been translated! */
123 return false;
124 #endif
127 void
128 IRBase::initFunctionStart(tree fn_decl, const Loc & loc)
130 init_function_start (fn_decl);
133 #if D_GCC_VER < 40
134 void
135 IRBase::addExp(tree e)
137 expand_expr_stmt_value(e, 0, 1);
139 #else
141 void
142 IRBase::addExp(tree e)
144 enum tree_code code = TREE_CODE (e);
146 /* Need to check that this is actually an expression; it
147 could be an integer constant (statement with no effect.)
148 Maybe should filter those out anyway... */
149 // C doesn't do this for label_exprs %% why?
150 if (EXPR_P(e) && ! EXPR_HAS_LOCATION (e))
151 SET_EXPR_LOCATION (e, input_location);
153 append_to_statement_list_force (e, & statementList);
156 void
157 IRBase::pushStatementList()
159 tree t;
160 t = alloc_stmt_list ();
161 TREE_CHAIN (t) = statementList;
162 statementList = t;
165 tree
166 IRBase::popStatementList()
168 tree t = statementList;
169 tree u;
170 tree chain = TREE_CHAIN(t);
171 TREE_CHAIN(t) = NULL_TREE;
172 statementList = chain;
174 // %% should gdc bother doing this?
176 /* If the statement list is completely empty, just return it. This is
177 just as good small as build_empty_stmt, with the advantage that
178 statement lists are merged when they appended to one another. So
179 using the STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P
180 statements. */
181 if (TREE_SIDE_EFFECTS (t))
183 tree_stmt_iterator i = tsi_start (t);
185 /* If the statement list contained exactly one statement, then
186 extract it immediately. */
187 if (tsi_one_before_end_p (i))
189 u = tsi_stmt (i);
190 tsi_delink (&i);
191 free_stmt_list (t);
192 t = u;
196 return t;
198 #endif
201 tree
202 IRBase::getLabelTree(LabelDsymbol * label)
204 if (! label->statement) {
205 error("undefined label %s", label->ident->string); // %% ident okay?
206 return NULL_TREE;
209 if (! label->statement->lblock) {
210 tree label_decl = build_decl (LABEL_DECL, get_identifier(label->ident->string), void_type_node);
212 assert(func != 0);
213 DECL_CONTEXT( label_decl ) = getLocalContext();
214 DECL_MODE( label_decl ) = VOIDmode; // Not sure why or if this is needed
215 // Not setting this doesn't seem to cause problems (unlike VAR_DECLs)
216 if (label->statement->loc.filename)
217 g.ofile->setDeclLoc( label_decl, label->statement->loc ); // %% label->loc okay?
218 label->statement->lblock = label_decl;
220 return label->statement->lblock;
223 IRBase::Flow *
224 IRBase::getLoopForLabel(Identifier * ident, bool want_continue)
226 if (ident) {
227 LabelStatement * lbl_stmt = func->searchLabel(ident)->statement;
228 assert(lbl_stmt != 0);
229 Statement * stmt = lbl_stmt->statement;
230 ScopeStatement * scope_stmt = stmt->isScopeStatement();
232 if (scope_stmt)
233 stmt = scope_stmt->statement;
235 for (int i = loops.dim - 1; i >= 0; i--) {
236 Flow * flow = (Flow *) loops.data[i];
238 if (flow->statement == stmt) {
239 if (want_continue)
240 assert(stmt->hasContinue());
241 return flow;
244 assert(0);
245 } else {
246 for (int i = loops.dim - 1; i >= 0; i--) {
247 Flow * flow = (Flow *) loops.data[i];
249 if (( ! want_continue && flow->statement->hasBreak() ) ||
250 flow->statement->hasContinue())
251 return flow;
253 assert(0);
257 #if D_GCC_VER < 40
259 IRBase::Flow *
260 IRBase::beginFlow(Statement * stmt, nesting * loop)
262 Flow * flow = new Flow;
264 flow->statement = stmt;
265 flow->loop = loop;
266 flow->exitLabel = NULL;
267 flow->overrideContinueLabel = NULL;
269 loops.push(flow);
271 return flow;
274 void
275 IRBase::endFlow()
277 Flow * flow;
279 assert(loops.dim);
281 flow = (Flow *) loops.pop();
282 if (flow->exitLabel)
283 expand_label(flow->exitLabel); // %% need a statement after this?
284 //%% delete flow;
287 void
288 IRBase::doLabel(tree t_label)
290 expand_label(t_label);
293 #else
295 IRBase::Flow *
296 IRBase::beginFlow(Statement * stmt/*, int labels*/)
298 Flow * flow = new Flow;
300 flow->statement = stmt;
301 flow->exitLabel = NULL_TREE;
302 flow->condition = NULL_TREE;
303 flow->trueBranch = NULL_TREE;
305 if (labels & Break)
306 flow->exitLabel = error_mark_node; // don't create until needed
307 if (labels & Continue) {
308 flow->continueLabel = build_decl(LABEL_DECL, NULL, void_type_node);
309 DECL_CONTEXT( flow->continueLabel ) = getLocalContext();
310 //used,mode?
312 flow->exitLabel = NULL;
315 loops.push(flow);
317 pushStatementList();
319 return flow;
322 void
323 IRBase::endFlow()
325 Flow * flow;
327 assert(loops.dim);
329 flow = (Flow *) loops.pop();
330 if (flow->exitLabel)
331 doLabel(flow->exitLabel);
332 //%% delete flow;
335 void
336 IRBase::doLabel(tree t_label)
338 addExp(build1(LABEL_EXPR, void_type_node, t_label));
341 #endif
343 extern "C" void pushlevel PARAMS ((int));
344 extern "C" tree poplevel PARAMS ((int, int, int));
345 extern "C" void set_block PARAMS ((tree));
346 extern "C" void insert_block PARAMS ((tree));
348 void IRBase::startScope()
350 unsigned * p_count = new unsigned;
351 *p_count = 0;
352 scopes.push(p_count);
354 //printf("%*sstartScope\n", scopes.dim, "");
355 startBindings();
358 void IRBase::endScope()
360 unsigned * p_count;
362 assert(scopes.dim);
363 p_count = (unsigned *) scopes.tos();
365 //endBindings();
367 //printf("%*s ending scope with %d left \n", scopes.dim, "", *p_count);
368 while ( *p_count )
369 endBindings();
370 scopes.pop();
371 //printf("%*sendScope\n", scopes.dim, "");
375 void IRBase::startBindings()
377 pushlevel(0);
378 tree block = make_node(BLOCK);
379 set_block(block);
381 #if D_GCC_VER < 40
382 // This is the key to getting local variables recorded for debugging.
383 // Simplying having the whole tree of BLOCKs doesn't matter as
384 // reorder_blocks will discard the whole thing.
385 expand_start_bindings_and_block(0, block);
386 #else
387 pushStatementList();
388 #endif
390 assert(scopes.dim);
391 ++( * (unsigned *) scopes.tos() );
392 //printf("%*s start -> %d\n", scopes.dim, "", * (unsigned *) scopes.tos() );
396 void IRBase::endBindings()
398 // %%TODO: reversing list causes problems with inf loops in unshare_all_decls
399 tree block = poplevel(1,0,0);
401 #if D_GCC_VER < 40
402 // %%TODO: DONT_JUMP_IN flag -- don't think DMD checks for
403 // jumping past initializations yet..
404 expand_end_bindings(NULL_TREE, 1, 0);
405 #else
406 tree t_body = popStatementList();
407 addExp(build3(BIND_EXPR, void_type_node,
408 BLOCK_VARS( block ), t_body, block));
409 #endif
411 // Because we used set_block, the popped level/block is not automatically recorded
412 insert_block(block);
414 assert(scopes.dim);
415 --( * (unsigned *) scopes.tos() );
416 assert( * (int *) scopes.tos() >= 0 );
417 //printf("%*s end -> %d\n", scopes.dim, "", * (unsigned *) scopes.tos() );