1
# DP: gccgo: Consider multi-result calls in escape analysis.
2
# DP: gccgo: Propagate escape info from closures to enclosed variables.
3
# DP: gccgo: Analyze function values and conversions.
4
# DP: gccgo: Use backend interface for stack allocation.
6
LANG=C svn diff -r222194:222657 gcc/go \
7
| sed -r 's,^--- (\S+)\t(\S+)(.*)$,--- a/src/\1\t\2,;s,^\+\+\+ (\S+)\t(\S+)(.*)$,+++ b/src/\1\t\2,'
11
2015-04-30 Chris Manghane <cmang@google.com>
13
* go-gcc.cc (Gcc_backend::stack_allocation_expression): New
16
Index: b/src/gcc/go/go-gcc.cc
17
===================================================================
18
--- a/src/gcc/go/go-gcc.cc
19
+++ b/src/gcc/go/go-gcc.cc
20
@@ -324,6 +324,9 @@ class Gcc_backend : public Backend
21
call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
22
Bexpression* static_chain, Location);
25
+ stack_allocation_expression(int64_t size, Location);
30
@@ -1884,6 +1887,17 @@ Gcc_backend::call_expression(Bexpression
31
return this->make_expression(ret);
34
+// Return an expression that allocates SIZE bytes on the stack.
37
+Gcc_backend::stack_allocation_expression(int64_t size, Location location)
39
+ tree alloca = builtin_decl_explicit(BUILT_IN_ALLOCA);
40
+ tree size_tree = build_int_cst(integer_type_node, size);
41
+ tree ret = build_call_expr_loc(location.gcc_location(), alloca, 1, size_tree);
42
+ return this->make_expression(ret);
45
// An expression as a statement.
48
Index: b/src/gcc/go/gofrontend/gogo.h
49
===================================================================
50
--- a/src/gcc/go/gofrontend/gogo.h
51
+++ b/src/gcc/go/gofrontend/gogo.h
52
@@ -1042,6 +1042,11 @@ class Function
53
this->is_unnamed_type_stub_method_ = true;
56
+ // Return the amount of enclosed variables in this closure.
58
+ closure_field_count() const
59
+ { return this->closure_fields_.size(); }
61
// Add a new field to the closure variable.
63
add_closure_field(Named_object* var, Location loc)
64
Index: b/src/gcc/go/gofrontend/expressions.h
65
===================================================================
66
--- a/src/gcc/go/gofrontend/expressions.h
67
+++ b/src/gcc/go/gofrontend/expressions.h
68
@@ -2786,7 +2786,7 @@ class Allocation_expression : public Exp
70
Allocation_expression(Type* type, Location location)
71
: Expression(EXPRESSION_ALLOCATION, location),
72
- type_(type), allocate_on_stack_(false), stack_temp_(NULL)
73
+ type_(type), allocate_on_stack_(false)
77
@@ -2807,9 +2807,6 @@ class Allocation_expression : public Exp
82
- do_flatten(Gogo*, Named_object*, Statement_inserter*);
85
do_get_backend(Translate_context*);
87
@@ -2821,9 +2818,6 @@ class Allocation_expression : public Exp
89
// Whether or not this is a stack allocation.
90
bool allocate_on_stack_;
91
- // If this memory is stack allocated, it will use the address of STACK_TEMP.
92
- // Otherwise, STACK_TEMP is NULL.
93
- Temporary_statement* stack_temp_;
96
// Construct a struct.
97
Index: b/src/gcc/go/gofrontend/backend.h
98
===================================================================
99
--- a/src/gcc/go/gofrontend/backend.h
100
+++ b/src/gcc/go/gofrontend/backend.h
101
@@ -377,6 +377,10 @@ class Backend
102
call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
103
Bexpression* static_chain, Location) = 0;
105
+ // Return an expression that allocates SIZE bytes on the stack.
106
+ virtual Bexpression*
107
+ stack_allocation_expression(int64_t size, Location) = 0;
111
// Create an error statement. This is used for cases which should
112
Index: b/src/gcc/go/gofrontend/escape.cc
113
===================================================================
114
--- a/src/gcc/go/gofrontend/escape.cc
115
+++ b/src/gcc/go/gofrontend/escape.cc
116
@@ -906,6 +906,8 @@ Build_connection_graphs::handle_composit
118
else if ((*p)->call_expression() != NULL)
119
this->handle_call(object, *p);
120
+ else if ((*p)->func_expression() != NULL)
121
+ composite_args.push_back((*p)->func_expression()->named_object());
122
else if ((*p)->is_composite_literal()
123
|| (*p)->heap_expression() != NULL)
124
this->handle_composite_literal(object, *p);
125
@@ -949,21 +951,24 @@ Build_connection_graphs::variable(Named_
129
- if (p->val == NULL)
130
+ Expression* def = p->val;
134
- if (p->val->func_expression() != NULL)
135
+ if (def->conversion_expression() != NULL)
136
+ def = def->conversion_expression()->expr();
137
+ if (def->func_expression() != NULL)
139
// VAR is being defined as a function object.
140
- Named_object* fn = p->val->func_expression()->named_object();
141
+ Named_object* fn = def->func_expression()->named_object();
142
Node* fn_node = this->gogo_->add_connection_node(fn);
143
var_node->add_edge(fn_node);
145
- else if(p->val->is_composite_literal()
146
- || p->val->heap_expression() != NULL)
147
- this->handle_composite_literal(var, p->val);
148
+ else if(def->is_composite_literal()
149
+ || def->heap_expression() != NULL)
150
+ this->handle_composite_literal(var, def);
152
- Named_object* ref = this->resolve_var_reference(p->val);
153
+ Named_object* ref = this->resolve_var_reference(def);
157
@@ -989,21 +994,21 @@ Build_connection_graphs::variable(Named_
158
Named_object* lhs_no = this->resolve_var_reference(assn->lhs());
159
Named_object* rhs_no = this->resolve_var_reference(assn->rhs());
161
- if (assn->rhs()->is_composite_literal()
162
- || assn->rhs()->heap_expression() != NULL)
163
- this->handle_composite_literal(var, assn->rhs());
164
- else if (assn->rhs()->call_result_expression() != NULL)
165
+ Expression* rhs = assn->rhs();
166
+ if (rhs->is_composite_literal()
167
+ || rhs->heap_expression() != NULL)
168
+ this->handle_composite_literal(var, rhs);
170
+ if (rhs->call_result_expression() != NULL)
172
// V's initialization will be a call result if
173
// V, V1 := call(VAR).
174
// There are no useful edges to make from V, but we want
175
// to make sure we handle the call that references VAR.
177
- assn->rhs()->call_result_expression()->call();
178
- this->handle_call(var, call);
179
+ rhs = rhs->call_result_expression()->call();
181
- else if (assn->rhs()->call_expression() != NULL)
182
- this->handle_call(var, assn->rhs());
183
+ if (rhs->call_expression() != NULL)
184
+ this->handle_call(var, rhs);
186
// If there is no standalone variable on the rhs, this could be a
187
// binary expression, which isn't interesting for analysis or a
188
@@ -1038,8 +1043,12 @@ Build_connection_graphs::variable(Named_
191
case Statement::STATEMENT_EXPRESSION:
192
- this->handle_call(var,
193
- p->statement->expression_statement()->expr());
195
+ Expression* call = p->statement->expression_statement()->expr();
196
+ if (call->call_result_expression() != NULL)
197
+ call = call->call_result_expression()->call();
198
+ this->handle_call(var, call);
202
case Statement::STATEMENT_GO:
203
@@ -1064,10 +1073,17 @@ Build_connection_graphs::variable(Named_
204
else if (cond->binary_expression() != NULL)
206
Binary_expression* comp = cond->binary_expression();
207
- if (comp->left()->call_expression() != NULL)
208
- this->handle_call(var, comp->left());
209
- if (comp->right()->call_expression() != NULL)
210
- this->handle_call(var, comp->right());
211
+ Expression* left = comp->left();
212
+ Expression* right = comp->right();
214
+ if (left->call_result_expression() != NULL)
215
+ left = left->call_result_expression()->call();
216
+ if (left->call_expression() != NULL)
217
+ this->handle_call(var, left);
218
+ if (right->call_result_expression() != NULL)
219
+ right = right->call_result_expression()->call();
220
+ if (right->call_expression() != NULL)
221
+ this->handle_call(var, right);
225
@@ -1092,16 +1108,10 @@ Build_connection_graphs::variable(Named_
226
// composite literal.
227
this->handle_composite_literal(decl_no, init);
229
- else if (init->call_result_expression() != NULL)
231
- // V's initialization will be a call result if
232
- // V, V1 := call(VAR).
233
- // There's no useful edges to make from V or V1, but we want
234
- // to make sure we handle the call that references VAR.
235
- Expression* call = init->call_result_expression()->call();
236
- this->handle_call(var, call);
238
- else if (init->call_expression() != NULL)
240
+ if (init->call_result_expression() != NULL)
241
+ init = init->call_result_expression()->call();
242
+ if (init->call_expression() != NULL)
243
this->handle_call(var, init);
246
@@ -1148,18 +1158,46 @@ Build_connection_graphs::statement(Block
250
- if (assn->rhs()->func_expression() != NULL)
251
+ Expression* rhs = assn->rhs();
252
+ if (rhs->temporary_reference_expression() != NULL)
253
+ rhs = rhs->temporary_reference_expression()->statement()->init();
257
+ if (rhs->call_result_expression() != NULL)
258
+ rhs = rhs->call_result_expression()->call();
259
+ if (rhs->call_expression() != NULL)
261
+ // It's not clear what variables we are trying to find references to
262
+ // so just use the arguments to this call.
263
+ Expression_list* args = rhs->call_expression()->args();
267
+ for (Expression_list::const_iterator p = args->begin();
271
+ Named_object* no = this->resolve_var_reference(*p);
273
+ Node* lhs_node = this->gogo_->add_connection_node(lhs_no);
274
+ Node* rhs_node = this->gogo_->add_connection_node(no);
275
+ lhs_node->add_edge(rhs_node);
279
+ this->handle_call(lhs_no, rhs);
281
+ else if (rhs->func_expression() != NULL)
283
Node* lhs_node = this->gogo_->add_connection_node(lhs_no);
284
- Named_object* fn = assn->rhs()->func_expression()->named_object();
285
+ Named_object* fn = rhs->func_expression()->named_object();
286
Node* fn_node = this->gogo_->add_connection_node(fn);
287
lhs_node->add_edge(fn_node);
289
- else if (assn->rhs()->call_expression() != NULL)
290
- this->handle_call(lhs_no, assn->rhs()->call_expression());
293
- Named_object* rhs_no = this->resolve_var_reference(assn->rhs());
294
+ Named_object* rhs_no = this->resolve_var_reference(rhs);
297
Node* lhs_node = this->gogo_->add_connection_node(lhs_no);
298
@@ -1188,6 +1226,8 @@ Build_connection_graphs::statement(Block
299
case Statement::STATEMENT_EXPRESSION:
301
Expression* expr = s->expression_statement()->expr();
302
+ if (expr->call_result_expression() != NULL)
303
+ expr = expr->call_result_expression()->call();
304
if (expr->call_expression() != NULL)
306
// It's not clear what variables we are trying to find references to
307
@@ -1208,6 +1248,73 @@ Build_connection_graphs::statement(Block
311
+ case Statement::STATEMENT_GO:
312
+ case Statement::STATEMENT_DEFER:
314
+ // Any variable referenced via a go or defer statement escapes to
315
+ // a different goroutine.
316
+ Expression* call = s->thunk_statement()->call();
317
+ if (call->call_expression() != NULL)
319
+ // It's not clear what variables we are trying to find references to
320
+ // so just use the arguments to this call.
321
+ Expression_list* args = call->call_expression()->args();
325
+ for (Expression_list::const_iterator p = args->begin();
329
+ Named_object* no = this->resolve_var_reference(*p);
331
+ this->handle_call(no, call);
337
+ case Statement::STATEMENT_VARIABLE_DECLARATION:
339
+ Variable_declaration_statement* decl =
340
+ s->variable_declaration_statement();
341
+ Named_object* decl_no = decl->var();
342
+ Variable* v = decl_no->var_value();
344
+ Expression* init = v->init();
348
+ if (init->is_composite_literal()
349
+ || init->heap_expression() != NULL)
351
+ // Create edges between DECL_NO and each named object in the
352
+ // composite literal.
353
+ this->handle_composite_literal(decl_no, init);
356
+ if (init->call_result_expression() != NULL)
357
+ init = init->call_result_expression()->call();
358
+ if (init->call_expression() != NULL)
360
+ // It's not clear what variables we are trying to find references to
361
+ // so just use the arguments to this call.
362
+ Expression_list* args = init->call_expression()->args();
366
+ for (Expression_list::const_iterator p = args->begin();
370
+ Named_object* no = this->resolve_var_reference(*p);
372
+ this->handle_call(no, init);
381
@@ -1276,8 +1383,22 @@ Gogo::analyze_reachability()
382
Node* m = worklist.front();
383
worklist.pop_front();
385
- for (std::set<Node*>::iterator n = m->edges().begin();
386
- n != m->edges().end();
387
+ std::set<Node*> reachable = m->edges();
388
+ if (m->object()->is_function()
389
+ && m->object()->func_value()->needs_closure())
391
+ // If a closure escapes everything it closes over also escapes.
392
+ Function* closure = m->object()->func_value();
393
+ for (size_t i = 0; i < closure->closure_field_count(); i++)
395
+ Named_object* enclosed = closure->enclosing_var(i);
396
+ Node* enclosed_node = this->lookup_connection_node(enclosed);
397
+ go_assert(enclosed_node != NULL);
398
+ reachable.insert(enclosed_node);
401
+ for (std::set<Node*>::iterator n = reachable.begin();
402
+ n != reachable.end();
405
// If an object can be reached from a node with ESCAPE_GLOBAL,
406
@@ -1296,7 +1417,7 @@ Gogo::analyze_reachability()
407
p != this->named_connection_nodes_.end();
410
- if (p->second->connection_node()->escape_state() == Node::ESCAPE_ARG)
411
+ if (p->second->connection_node()->escape_state() < Node::ESCAPE_NONE)
412
worklist.push_back(p->second);
415
@@ -1305,15 +1426,30 @@ Gogo::analyze_reachability()
416
Node* m = worklist.front();
417
worklist.pop_front();
419
- for (std::set<Node*>::iterator n = m->edges().begin();
420
- n != m->edges().end();
421
+ std::set<Node*> reachable = m->edges();
422
+ if (m->object()->is_function()
423
+ && m->object()->func_value()->needs_closure())
425
+ // If a closure escapes everything it closes over also escapes.
426
+ Function* closure = m->object()->func_value();
427
+ for (size_t i = 0; i < closure->closure_field_count(); i++)
429
+ Named_object* enclosed = closure->enclosing_var(i);
430
+ Node* enclosed_node = this->lookup_connection_node(enclosed);
431
+ go_assert(enclosed_node != NULL);
432
+ reachable.insert(enclosed_node);
435
+ for (std::set<Node*>::iterator n = reachable.begin();
436
+ n != reachable.end();
439
// If an object can be reached from a node with ESCAPE_ARG,
440
// it is ESCAPE_ARG or ESCAPE_GLOBAL.
441
- if ((*n)->connection_node()->escape_state() > Node::ESCAPE_ARG)
442
+ Node::Escapement_lattice e = m->connection_node()->escape_state();
443
+ if ((*n)->connection_node()->escape_state() > e)
445
- (*n)->connection_node()->set_escape_state(Node::ESCAPE_ARG);
446
+ (*n)->connection_node()->set_escape_state(e);
447
worklist.push_back(*n);
450
@@ -1429,8 +1565,7 @@ Optimize_allocations::variable(Named_obj
452
if (var->is_variable())
454
- if (var->var_value()->is_address_taken())
455
- var->var_value()->set_does_not_escape();
456
+ var->var_value()->set_does_not_escape();
457
if (var->var_value()->init() != NULL
458
&& var->var_value()->init()->allocation_expression() != NULL)
460
@@ -1439,9 +1574,6 @@ Optimize_allocations::variable(Named_obj
461
alloc->set_allocate_on_stack();
464
- else if (var->is_result_variable()
465
- && var->result_var_value()->is_address_taken())
466
- var->result_var_value()->set_does_not_escape();
468
return TRAVERSE_CONTINUE;
470
Index: b/src/gcc/go/gofrontend/expressions.cc
471
===================================================================
472
--- a/src/gcc/go/gofrontend/expressions.cc
473
+++ b/src/gcc/go/gofrontend/expressions.cc
474
@@ -11430,20 +11430,6 @@ Allocation_expression::do_copy()
479
-Allocation_expression::do_flatten(Gogo*, Named_object*,
480
- Statement_inserter* inserter)
482
- if (this->allocate_on_stack_)
484
- this->stack_temp_ = Statement::make_temporary(this->type_, NULL,
486
- this->stack_temp_->set_is_address_taken();
487
- inserter->insert(this->stack_temp_);
492
// Return the backend representation for an allocation expression.
495
@@ -11452,17 +11438,16 @@ Allocation_expression::do_get_backend(Tr
496
Gogo* gogo = context->gogo();
497
Location loc = this->location();
499
- if (this->stack_temp_ != NULL)
500
+ Btype* btype = this->type_->get_backend(gogo);
501
+ if (this->allocate_on_stack_)
504
- Expression::make_temporary_reference(this->stack_temp_, loc);
505
- ref = Expression::make_unary(OPERATOR_AND, ref, loc);
506
- return ref->get_backend(context);
507
+ int64_t size = gogo->backend()->type_size(btype);
508
+ return gogo->backend()->stack_allocation_expression(size, loc);
512
gogo->allocate_memory(this->type_, loc)->get_backend(context);
513
- Btype* pbtype = gogo->backend()->pointer_type(this->type_->get_backend(gogo));
514
+ Btype* pbtype = gogo->backend()->pointer_type(btype);
515
return gogo->backend()->convert_expression(pbtype, space, loc);