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 #include "d-irstate.h"
29 #include "d-codegen.h"
32 Array
IRBase::deferredFuncDecls
;
40 // declContextStack is composed... choose one..
42 statementList
= NULL_TREE
;
47 IRBase::startFunction(FuncDeclaration
* decl
)
49 IRState
* new_irs
= new IRState();
50 new_irs
->parent
= g
.irs
;
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())
64 else if (decl
->isStaticDestructor())
66 else if (decl
->isUnitTestDeclaration())
67 mi
.unitTests
.push(decl
);
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
;
84 a
.append(& deferredFuncDecls
);
85 deferredFuncDecls
.setDim(0);
86 for (unsigned i
= 0; i
< a
.dim
; i
++) {
87 FuncDeclaration
* f
= (FuncDeclaration
*) a
.data
[i
];
100 IRBase::shouldDeferFunction(FuncDeclaration
* decl
)
103 if (! func
|| gen
.functionNeedsChain(decl
)) {
106 deferredFuncDecls
.push(decl
);
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
121 the method is in the nested cgraph nodes, but the function hasing
122 even been translated! */
128 IRBase::initFunctionStart(tree fn_decl
, const Loc
& loc
)
130 init_function_start (fn_decl
);
135 IRBase::addExp(tree e
)
137 expand_expr_stmt_value(e
, 0, 1);
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
);
157 IRBase::pushStatementList()
160 t
= alloc_stmt_list ();
161 TREE_CHAIN (t
) = statementList
;
166 IRBase::popStatementList()
168 tree t
= statementList
;
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
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
))
202 IRBase::getLabelTree(LabelDsymbol
* label
)
204 if (! label
->statement
) {
205 error("undefined label %s", label
->ident
->string
); // %% ident okay?
209 if (! label
->statement
->lblock
) {
210 tree label_decl
= build_decl (LABEL_DECL
, get_identifier(label
->ident
->string
), void_type_node
);
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
;
224 IRBase::getLoopForLabel(Identifier
* ident
, bool want_continue
)
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();
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
) {
240 assert(stmt
->hasContinue());
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())
260 IRBase::beginFlow(Statement
* stmt
, nesting
* loop
)
262 Flow
* flow
= new Flow
;
264 flow
->statement
= stmt
;
266 flow
->exitLabel
= NULL
;
267 flow
->overrideContinueLabel
= NULL
;
281 flow
= (Flow
*) loops
.pop();
283 expand_label(flow
->exitLabel
); // %% need a statement after this?
288 IRBase::doLabel(tree t_label
)
290 expand_label(t_label
);
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
;
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();
312 flow->exitLabel = NULL;
329 flow
= (Flow
*) loops
.pop();
331 doLabel(flow
->exitLabel
);
336 IRBase::doLabel(tree t_label
)
338 addExp(build1(LABEL_EXPR
, void_type_node
, t_label
));
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;
352 scopes
.push(p_count
);
354 //printf("%*sstartScope\n", scopes.dim, "");
358 void IRBase::endScope()
363 p_count
= (unsigned *) scopes
.tos();
367 //printf("%*s ending scope with %d left \n", scopes.dim, "", *p_count);
371 //printf("%*sendScope\n", scopes.dim, "");
375 void IRBase::startBindings()
378 tree block
= make_node(BLOCK
);
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
);
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);
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);
406 tree t_body
= popStatementList();
407 addExp(build3(BIND_EXPR
, void_type_node
,
408 BLOCK_VARS( block
), t_body
, block
));
411 // Because we used set_block, the popped level/block is not automatically recorded
415 --( * (unsigned *) scopes
.tos() );
416 assert( * (int *) scopes
.tos() >= 0 );
417 //printf("%*s end -> %d\n", scopes.dim, "", * (unsigned *) scopes.tos() );