~angelsl/ubuntu/wily/gcc-5/mips-cross

« back to all changes in this revision

Viewing changes to debian/patches/go-escape-analysis2.diff

  • Committer: angelsl
  • Date: 2015-10-30 03:30:35 UTC
  • Revision ID: angelsl-20151030033035-rmug41zm8hyjgisg
Original import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
5
 
 
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,'
 
8
 
 
9
gcc/go/
 
10
 
 
11
2015-04-30  Chris Manghane  <cmang@google.com>
 
12
 
 
13
        * go-gcc.cc (Gcc_backend::stack_allocation_expression): New
 
14
        method.
 
15
 
 
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);
 
23
 
 
24
+  Bexpression*
 
25
+  stack_allocation_expression(int64_t size, Location);
 
26
+
 
27
   // Statements.
 
28
 
 
29
   Bstatement*
 
30
@@ -1884,6 +1887,17 @@ Gcc_backend::call_expression(Bexpression
 
31
   return this->make_expression(ret);
 
32
 }
 
33
 
 
34
+// Return an expression that allocates SIZE bytes on the stack.
 
35
+
 
36
+Bexpression*
 
37
+Gcc_backend::stack_allocation_expression(int64_t size, Location location)
 
38
+{
 
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);
 
43
+}
 
44
+
 
45
 // An expression as a statement.
 
46
 
 
47
 Bstatement*
 
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;
 
54
   }
 
55
 
 
56
+  // Return the amount of enclosed variables in this closure.
 
57
+  size_t
 
58
+  closure_field_count() const
 
59
+  { return this->closure_fields_.size(); }
 
60
+
 
61
   // Add a new field to the closure variable.
 
62
   void
 
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
 
69
  public:
 
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)
 
74
   { }
 
75
 
 
76
   void
 
77
@@ -2807,9 +2807,6 @@ class Allocation_expression : public Exp
 
78
   Expression*
 
79
   do_copy();
 
80
 
 
81
-  Expression*
 
82
-  do_flatten(Gogo*, Named_object*, Statement_inserter*);
 
83
-
 
84
   Bexpression*
 
85
   do_get_backend(Translate_context*);
 
86
 
 
87
@@ -2821,9 +2818,6 @@ class Allocation_expression : public Exp
 
88
   Type* type_;
 
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_;
 
94
 };
 
95
 
 
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;
 
104
 
 
105
+  // Return an expression that allocates SIZE bytes on the stack.
 
106
+  virtual Bexpression*
 
107
+  stack_allocation_expression(int64_t size, Location) = 0;
 
108
+
 
109
   // Statements.
 
110
 
 
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
 
117
        continue;
 
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_
 
126
           p != defs->end();
 
127
           ++p)
 
128
        {
 
129
-         if (p->val == NULL)
 
130
+         Expression* def = p->val;
 
131
+         if (def == NULL)
 
132
            continue;
 
133
 
 
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)
 
138
            {
 
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);
 
144
            }
 
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);
 
151
 
 
152
-         Named_object* ref = this->resolve_var_reference(p->val);
 
153
+         Named_object* ref = this->resolve_var_reference(def);
 
154
          if (ref == NULL)
 
155
            continue;
 
156
 
 
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());
 
160
 
 
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);
 
169
+
 
170
+             if (rhs->call_result_expression() != NULL)
 
171
                {
 
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.
 
176
-                 Expression* call =
 
177
-                   assn->rhs()->call_result_expression()->call();
 
178
-                 this->handle_call(var, call);
 
179
+                 rhs = rhs->call_result_expression()->call();
 
180
                }
 
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);
 
185
 
 
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_
 
189
            break;
 
190
 
 
191
          case Statement::STATEMENT_EXPRESSION:
 
192
-           this->handle_call(var,
 
193
-                             p->statement->expression_statement()->expr());
 
194
+           {
 
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);
 
199
+           }
 
200
            break;
 
201
 
 
202
          case Statement::STATEMENT_GO:
 
203
@@ -1064,10 +1073,17 @@ Build_connection_graphs::variable(Named_
 
204
              else if (cond->binary_expression() != NULL)
 
205
                {
 
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();
 
213
+
 
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);
 
222
                }
 
223
            }
 
224
            break;
 
225
@@ -1092,16 +1108,10 @@ Build_connection_graphs::variable(Named_
 
226
                  // composite literal.
 
227
                  this->handle_composite_literal(decl_no, init);
 
228
                }
 
229
-             else if (init->call_result_expression() != NULL)
 
230
-               {
 
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);
 
237
-               }
 
238
-             else if (init->call_expression() != NULL)
 
239
+
 
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);
 
244
            }
 
245
            break;
 
246
@@ -1148,18 +1158,46 @@ Build_connection_graphs::statement(Block
 
247
       if (lhs_no == NULL)
 
248
        break;
 
249
 
 
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();
 
254
+      if (rhs == NULL)
 
255
+       break;
 
256
+
 
257
+      if (rhs->call_result_expression() != NULL)
 
258
+       rhs = rhs->call_result_expression()->call();
 
259
+      if (rhs->call_expression() != NULL)
 
260
+       {
 
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();
 
264
+         if (args == NULL)
 
265
+           break;
 
266
+
 
267
+         for (Expression_list::const_iterator p = args->begin();
 
268
+              p != args->end();
 
269
+              ++p)
 
270
+           {
 
271
+             Named_object* no = this->resolve_var_reference(*p);
 
272
+             if (no != NULL) {
 
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);
 
276
+             }
 
277
+           }
 
278
+
 
279
+         this->handle_call(lhs_no, rhs);
 
280
+       }
 
281
+      else if (rhs->func_expression() != NULL)
 
282
        {
 
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);
 
288
        }
 
289
-      else if (assn->rhs()->call_expression() != NULL)
 
290
-       this->handle_call(lhs_no, assn->rhs()->call_expression());
 
291
       else
 
292
        {
 
293
-         Named_object* rhs_no = this->resolve_var_reference(assn->rhs());
 
294
+         Named_object* rhs_no = this->resolve_var_reference(rhs);
 
295
          if (rhs_no != NULL)
 
296
            {
 
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:
 
300
     {
 
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)
 
305
        {
 
306
          // It's not clear what variables we are trying to find references to
 
307
@@ -1208,6 +1248,73 @@ Build_connection_graphs::statement(Block
 
308
     }
 
309
     break;
 
310
 
 
311
+  case Statement::STATEMENT_GO:
 
312
+  case Statement::STATEMENT_DEFER:
 
313
+    {
 
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)
 
318
+       {
 
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();
 
322
+         if (args == NULL)
 
323
+           break;
 
324
+
 
325
+         for (Expression_list::const_iterator p = args->begin();
 
326
+              p != args->end();
 
327
+              ++p)
 
328
+           {
 
329
+             Named_object* no = this->resolve_var_reference(*p);
 
330
+             if (no != NULL)
 
331
+               this->handle_call(no, call);
 
332
+           }
 
333
+       }
 
334
+    }
 
335
+    break;
 
336
+
 
337
+  case Statement::STATEMENT_VARIABLE_DECLARATION:
 
338
+    {
 
339
+      Variable_declaration_statement* decl =
 
340
+       s->variable_declaration_statement();
 
341
+      Named_object* decl_no = decl->var();
 
342
+      Variable* v = decl_no->var_value();
 
343
+
 
344
+      Expression* init = v->init();
 
345
+      if (init == NULL)
 
346
+       break;
 
347
+
 
348
+      if (init->is_composite_literal()
 
349
+         || init->heap_expression() != NULL)
 
350
+       {
 
351
+         // Create edges between DECL_NO and each named object in the
 
352
+         // composite literal.
 
353
+         this->handle_composite_literal(decl_no, init);
 
354
+       }
 
355
+
 
356
+      if (init->call_result_expression() != NULL)
 
357
+       init = init->call_result_expression()->call();
 
358
+      if (init->call_expression() != NULL)
 
359
+       {
 
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();
 
363
+         if (args == NULL)
 
364
+           break;
 
365
+
 
366
+         for (Expression_list::const_iterator p = args->begin();
 
367
+              p != args->end();
 
368
+              ++p)
 
369
+           {
 
370
+             Named_object* no = this->resolve_var_reference(*p);
 
371
+             if (no != NULL)
 
372
+               this->handle_call(no, init);
 
373
+           }
 
374
+       }
 
375
+    }
 
376
+    break;
 
377
+
 
378
   default:
 
379
     break;
 
380
   }
 
381
@@ -1276,8 +1383,22 @@ Gogo::analyze_reachability()
 
382
       Node* m = worklist.front();
 
383
       worklist.pop_front();
 
384
 
 
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())
 
390
+       {
 
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++)
 
394
+           {
 
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);
 
399
+           }
 
400
+       }
 
401
+      for (std::set<Node*>::iterator n = reachable.begin();
 
402
+          n != reachable.end();
 
403
           ++n)
 
404
        {
 
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();
 
408
        ++p)
 
409
     {
 
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);
 
413
     }
 
414
 
 
415
@@ -1305,15 +1426,30 @@ Gogo::analyze_reachability()
 
416
       Node* m = worklist.front();
 
417
       worklist.pop_front();
 
418
 
 
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())
 
424
+       {
 
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++)
 
428
+           {
 
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);
 
433
+           }
 
434
+       }
 
435
+      for (std::set<Node*>::iterator n = reachable.begin();
 
436
+          n != reachable.end();
 
437
           ++n)
 
438
        {
 
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)
 
444
            {
 
445
-             (*n)->connection_node()->set_escape_state(Node::ESCAPE_ARG);
 
446
+             (*n)->connection_node()->set_escape_state(e);
 
447
              worklist.push_back(*n);
 
448
            }
 
449
        }
 
450
@@ -1429,8 +1565,7 @@ Optimize_allocations::variable(Named_obj
 
451
 
 
452
   if (var->is_variable())
 
453
     {
 
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)
 
459
        {
 
460
@@ -1439,9 +1574,6 @@ Optimize_allocations::variable(Named_obj
 
461
          alloc->set_allocate_on_stack();
 
462
        }
 
463
     }
 
464
-  else if (var->is_result_variable()
 
465
-          && var->result_var_value()->is_address_taken())
 
466
-    var->result_var_value()->set_does_not_escape();
 
467
 
 
468
   return TRAVERSE_CONTINUE;
 
469
 }
 
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()
 
475
   return alloc;
 
476
 }
 
477
 
 
478
-Expression*
 
479
-Allocation_expression::do_flatten(Gogo*, Named_object*,
 
480
-                                 Statement_inserter* inserter)
 
481
-{
 
482
-  if (this->allocate_on_stack_)
 
483
-    {
 
484
-      this->stack_temp_ = Statement::make_temporary(this->type_, NULL,
 
485
-                                                   this->location());
 
486
-      this->stack_temp_->set_is_address_taken();
 
487
-      inserter->insert(this->stack_temp_);
 
488
-    }
 
489
-  return this;
 
490
-}
 
491
-
 
492
 // Return the backend representation for an allocation expression.
 
493
 
 
494
 Bexpression*
 
495
@@ -11452,17 +11438,16 @@ Allocation_expression::do_get_backend(Tr
 
496
   Gogo* gogo = context->gogo();
 
497
   Location loc = this->location();
 
498
 
 
499
-  if (this->stack_temp_ != NULL)
 
500
+  Btype* btype = this->type_->get_backend(gogo);
 
501
+  if (this->allocate_on_stack_)
 
502
     {
 
503
-      Expression* ref =
 
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);
 
509
     }
 
510
 
 
511
   Bexpression* space = 
 
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);
 
516
 }
 
517