aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-08-17 23:43:08 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-08-17 23:43:08 +0000
commite68035acfd6997ed97eb32aec4f277f3b6858550 (patch)
treef0e21a4a0680568bf5045771a16e20292aad1cfc /gcc
parentb9a21efdea18862f79c68ceb2eee0704844ead53 (diff)
downloadgcc-e68035acfd6997ed97eb32aec4f277f3b6858550.zip
gcc-e68035acfd6997ed97eb32aec4f277f3b6858550.tar.gz
gcc-e68035acfd6997ed97eb32aec4f277f3b6858550.tar.bz2
compiler, runtime: allocate defer records on the stack
When a defer is executed at most once in a function body, we can allocate the defer record for it on the stack instead of on the heap. This should make defers like this (which are very common) faster. This is a port of CL 171758 from the gc repo. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/190410 From-SVN: r274613
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/runtime.def4
-rw-r--r--gcc/go/gofrontend/statements.cc42
-rw-r--r--gcc/go/gofrontend/statements.h19
4 files changed, 62 insertions, 5 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 78597da..ef5bb41 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-838f926c93898767f0337122725a4f52a1335186
+4b47cadf938caadf563f8d0bb3f7111d06f61752
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index dfd6ebd..7eac880 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -287,6 +287,10 @@ DEF_GO_RUNTIME(GO, "__go_go", P2(UINTPTR, POINTER), R1(POINTER))
DEF_GO_RUNTIME(DEFERPROC, "runtime.deferproc", P3(BOOLPTR, UINTPTR, POINTER),
R0())
+// Defer a function, with stack-allocated defer structure.
+DEF_GO_RUNTIME(DEFERPROCSTACK, "runtime.deferprocStack",
+ P4(POINTER, BOOLPTR, UINTPTR, POINTER), R0())
+
// Convert an empty interface to an empty interface, returning ok.
DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL))
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 6d9c0eb..27c309e 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -2614,7 +2614,11 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
if (this->classification() == STATEMENT_GO)
s = Statement::make_go_statement(call, location);
else if (this->classification() == STATEMENT_DEFER)
- s = Statement::make_defer_statement(call, location);
+ {
+ s = Statement::make_defer_statement(call, location);
+ if ((Node::make_node(this)->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
+ s->defer_statement()->set_on_stack();
+ }
else
go_unreachable();
@@ -3019,13 +3023,45 @@ Defer_statement::do_get_backend(Translate_context* context)
Location loc = this->location();
Expression* ds = context->function()->func_value()->defer_stack(loc);
- Expression* call = Runtime::make_call(Runtime::DEFERPROC, loc, 3,
- ds, fn, arg);
+ Expression* call;
+ if (this->on_stack_)
+ {
+ if (context->gogo()->debug_optimization())
+ go_debug(loc, "stack allocated defer");
+
+ Type* defer_type = Defer_statement::defer_struct_type();
+ Expression* defer = Expression::make_allocation(defer_type, loc);
+ defer->allocation_expression()->set_allocate_on_stack();
+ defer->allocation_expression()->set_no_zero();
+ call = Runtime::make_call(Runtime::DEFERPROCSTACK, loc, 4,
+ defer, ds, fn, arg);
+ }
+ else
+ call = Runtime::make_call(Runtime::DEFERPROC, loc, 3,
+ ds, fn, arg);
Bexpression* bcall = call->get_backend(context);
Bfunction* bfunction = context->function()->func_value()->get_decl();
return context->backend()->expression_statement(bfunction, bcall);
}
+Type*
+Defer_statement::defer_struct_type()
+{
+ Type* ptr_type = Type::make_pointer_type(Type::make_void_type());
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ Type* bool_type = Type::make_boolean_type();
+ return Type::make_builtin_struct_type(9,
+ "link", ptr_type,
+ "frame", ptr_type,
+ "panicStack", ptr_type,
+ "_panic", ptr_type,
+ "pfn", uintptr_type,
+ "arg", ptr_type,
+ "retaddr", uintptr_type,
+ "makefunccanrecover", bool_type,
+ "heap", bool_type);
+}
+
// Dump the AST representation for defer statement.
void
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 7c254d0..311bbaa 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -24,6 +24,7 @@ class Expression_statement;
class Block_statement;
class Return_statement;
class Thunk_statement;
+class Defer_statement;
class Goto_statement;
class Goto_unnamed_statement;
class Label_statement;
@@ -403,6 +404,11 @@ class Statement
Thunk_statement*
thunk_statement();
+ // If this is a defer statement, return it. Otherwise return NULL.
+ Defer_statement*
+ defer_statement()
+ { return this->convert<Defer_statement, STATEMENT_DEFER>(); }
+
// If this is a goto statement, return it. Otherwise return NULL.
Goto_statement*
goto_statement()
@@ -1419,15 +1425,26 @@ class Defer_statement : public Thunk_statement
{
public:
Defer_statement(Call_expression* call, Location location)
- : Thunk_statement(STATEMENT_DEFER, call, location)
+ : Thunk_statement(STATEMENT_DEFER, call, location),
+ on_stack_(false)
{ }
+ void
+ set_on_stack()
+ { this->on_stack_ = true; }
+
protected:
Bstatement*
do_get_backend(Translate_context*);
void
do_dump_statement(Ast_dump_context*) const;
+
+ private:
+ static Type*
+ defer_struct_type();
+
+ bool on_stack_;
};
// A goto statement.