This patch to the Go frontend by Cherry Zhang stack allocates defer thunk when possible, which is to say when the defer statement is not in a loop. Bootstrapped on x86_64-pc-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 256407) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -d5774539b17112d9ce709a1fe722daf68eb8594f +7c5e4d67041e3529a055a923b2b9f5ef09aa72a3 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/escape.cc =================================================================== --- gcc/go/gofrontend/escape.cc (revision 256405) +++ gcc/go/gofrontend/escape.cc (working copy) @@ -1420,7 +1420,14 @@ Escape_analysis_assign::statement(Block* case Statement::STATEMENT_DEFER: if (this->context_->loop_depth() == 1) - break; + { + // Defer statement may need to allocate a thunk. When it is + // not inside a loop, this can be stack allocated, as it + // runs before the function finishes. + Node* n = Node::make_node(s); + n->set_encoding(Node::ESCAPE_NONE); + break; + } // fallthrough case Statement::STATEMENT_GO: Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 256366) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -2156,6 +2156,8 @@ Thunk_statement::simplify_statement(Gogo // Allocate the initialized struct on the heap. constructor = Expression::make_heap_expression(constructor, location); + if ((Node::make_node(this)->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE) + constructor->heap_expression()->set_allocate_on_stack(); // Throw an error if the function is nil. This is so that for `go // nil` we get a backtrace from the go statement, rather than a