Commit 862ec763 by Ian Lance Taylor Committed by Ian Lance Taylor

compiler: import inlinable functions from package data

    
    Start reading the export data generated by the last change in this
    series.  At this point we will inline direct calls to empty functions
    and methods defined in different packages.
    
    Reviewed-on: https://go-review.googlesource.com/c/150062

From-SVN: r266517
parent 56c79e7f
2018-11-27 Ian Lance Taylor <iant@golang.org>
* go-gcc.cc (Gcc_backend::function): Handle function_only_inline
flag.
2018-11-13 David Malcolm <dmalcolm@redhat.com>
* go-gcc-diagnostics.cc: Replace "source_location" with "location_t".
......
......@@ -3086,6 +3086,11 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
TREE_THIS_VOLATILE(decl) = 1;
if ((flags & function_in_unique_section) != 0)
resolve_unique_section(decl, 0, 1);
if ((flags & function_only_inline) != 0)
{
DECL_EXTERNAL(decl) = 1;
DECL_DECLARED_INLINE_P(decl) = 1;
}
go_preserve_from_gc(decl);
return new Bfunction(decl);
......
3ecc845c337c15d9a19ed8d277e5ee9eaf49c3ad
f551ab95f46c3d7bb7c032711e10b03bfa995ee2
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
......@@ -726,6 +726,13 @@ class Backend
// possible. This is used for field tracking.
static const unsigned int function_in_unique_section = 1 << 5;
// Set if the function should be available for inlining in the
// backend, but should not be emitted as a standalone function. Any
// call to the function that is not inlined should be treated as a
// call to a function defined in a different compilation unit. This
// is like a C99 function marked inline but not extern.
static const unsigned int function_only_inline = 1 << 6;
// Declare or define a function of FNTYPE.
// NAME is the Go name of the function. ASM_NAME, if not the empty
// string, is the name that should be used in the symbol table; this
......
......@@ -9785,6 +9785,15 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
}
}
// If this is a call to an imported function for which we have an
// inlinable function body, add it to the list of functions to give
// to the backend as inlining opportunities.
Func_expression* fe = this->fn_->func_expression();
if (fe != NULL
&& fe->named_object()->is_function_declaration()
&& fe->named_object()->func_declaration_value()->has_imported_body())
gogo->add_imported_inlinable_function(fe->named_object());
return this;
}
......
......@@ -97,8 +97,6 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
}
}
::gogo->linemap()->stop();
::gogo->clear_file_scope();
// If the global predeclared names are referenced but not defined,
......@@ -122,6 +120,10 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
// form which is easier to use.
::gogo->lower_parse_tree();
// At this point we have handled all inline functions, so we no
// longer need the linemap.
::gogo->linemap()->stop();
// Create function descriptors as needed.
::gogo->create_function_descriptors();
......
......@@ -43,6 +43,7 @@ class Backend;
class Export;
class Export_function_body;
class Import;
class Import_function_body;
class Bexpression;
class Btype;
class Bstatement;
......@@ -420,6 +421,17 @@ class Gogo
Named_object*
declare_package_function(const std::string&, Function_type*, Location);
// Add a function declaration to the list of functions we may want
// to inline.
void
add_imported_inlinable_function(Named_object*);
// Add a function to the list of functions that we do want to
// inline.
void
add_imported_inline_function(Named_object* no)
{ this->imported_inline_functions_.push_back(no); }
// Add a label.
Label*
add_label_definition(const std::string&, Location);
......@@ -661,7 +673,7 @@ class Gogo
propagate_escape(Escape_context*, Node*);
// Add notes about the escape level of a function's input and output
// parameters for exporting and importing top level functions.
// parameters for exporting and importing top level functions.
void
tag_function(Escape_context*, Named_object*);
......@@ -726,7 +738,7 @@ class Gogo
void
simplify_thunk_statements();
// Dump AST if -fgo-dump-ast is set
// Dump AST if -fgo-dump-ast is set.
void
dump_ast(const char* basename);
......@@ -1062,6 +1074,12 @@ class Gogo
std::vector<Analysis_set> analysis_sets_;
// A list of objects to add to the GC roots.
std::vector<Expression*> gc_roots_;
// A list of function declarations with imported bodies that we may
// want to inline.
std::vector<Named_object*> imported_inlinable_functions_;
// A list of functions that we want to inline. These will be sent
// to the backend.
std::vector<Named_object*> imported_inline_functions_;
};
// A block of statements.
......@@ -1144,6 +1162,10 @@ class Block
void
export_block(Export_function_body*);
// Turn exported block data into a block.
static bool
import_block(Block*, Import_function_body*, Location);
// Convert the block to the backend representation.
Bblock*
get_backend(Translate_context*);
......@@ -1419,6 +1441,17 @@ class Function
set_export_for_inlining()
{ this->export_for_inlining_ = true; }
// Return whether this function is inline only.
bool
is_inline_only() const
{ return this->is_inline_only_; }
// Mark the function as inline only: the body should not be emitted
// if it is not inlined.
void
set_is_inline_only()
{ this->is_inline_only_ = true; }
// Swap with another function. Used only for the thunk which calls
// recover.
void
......@@ -1476,14 +1509,15 @@ class Function
// Export a function with a type.
static void
export_func_with_type(Export*, const std::string& name,
const Function_type*, bool nointerface, Block* block);
const Function_type*, bool nointerface, Block* block,
Location);
// Import a function.
static void
import_func(Import*, std::string* pname, Typed_identifier** receiver,
Typed_identifier_list** pparameters,
Typed_identifier_list** presults, bool* is_varargs,
bool* nointerface);
bool* nointerface, std::string* body);
private:
// Type for mapping from label names to Label objects.
......@@ -1557,6 +1591,9 @@ class Function
// True if we should export the body of this function for
// cross-package inlining.
bool export_for_inlining_ : 1;
// True if this function is inline only: if it should not be emitted
// if it is not inlined.
bool is_inline_only_ : 1;
};
// A snapshot of the current binding state.
......@@ -1600,7 +1637,8 @@ class Function_declaration
public:
Function_declaration(Function_type* fntype, Location location)
: fntype_(fntype), location_(location), asm_name_(), descriptor_(NULL),
fndecl_(NULL), pragmas_(0)
fndecl_(NULL), pragmas_(0), imported_body_(),
is_on_inlinable_list_(false)
{ }
Function_type*
......@@ -1646,6 +1684,30 @@ class Function_declaration
void
set_nointerface();
// Whether we have an imported function body.
bool
has_imported_body() const
{ return !this->imported_body_.empty(); }
// Record the imported body of this function.
void
set_imported_body(const std::string& imported_body)
{ this->imported_body_ = imported_body; }
// Whether this declaration is on the list of inlinable functions.
bool
is_on_inlinable_list() const
{ return this->is_on_inlinable_list_; }
// Set that this function is on the list of inlinable functions.
void
set_is_on_inlinable_list()
{ this->is_on_inlinable_list_ = true; }
// Import the function body, creating a function.
void
import_function_body(Gogo*, Named_object*);
// Return an expression for the function descriptor, given the named
// object for this function. This may only be called for functions
// without a closure. This will be an immutable struct with one
......@@ -1673,7 +1735,7 @@ class Function_declaration
{
Function::export_func_with_type(exp, name, this->fntype_,
this->is_method() && this->nointerface(),
NULL);
NULL, this->location_);
}
// Check that the types used in this declaration's signature are defined.
......@@ -1694,6 +1756,10 @@ class Function_declaration
Bfunction* fndecl_;
// Pragmas for this function. This is a set of GOPRAGMA bits.
unsigned int pragmas_;
// Export data for function body if imported from a different package.
std::string imported_body_;
// Whether this declaration is already on the list of inlinable functions.
bool is_on_inlinable_list_;
};
// A variable.
......@@ -1789,7 +1855,7 @@ class Variable
bool
is_in_heap() const
{
return this->is_address_taken_
return this->is_address_taken_
&& this->escapes_
&& !this->is_global_;
}
......@@ -2103,7 +2169,7 @@ class Result_variable
void
set_non_escaping_address_taken()
{ this->is_non_escaping_address_taken_ = true; }
// Return whether this variable escapes the function it is declared in.
bool
escapes()
......@@ -3200,7 +3266,7 @@ class Package
// Return the bindings.
Bindings*
bindings()
bindings() const
{ return this->bindings_; }
// Type used to map import names to package aliases.
......
......@@ -744,8 +744,9 @@ Import::import_func(Package* package)
Typed_identifier_list* results;
bool is_varargs;
bool nointerface;
Function::import_func(this, &name, &receiver,
&parameters, &results, &is_varargs, &nointerface);
std::string body;
Function::import_func(this, &name, &receiver, &parameters, &results,
&is_varargs, &nointerface, &body);
Function_type *fntype = Type::make_function_type(receiver, parameters,
results, this->location_);
if (is_varargs)
......@@ -788,6 +789,8 @@ Import::import_func(Package* package)
if (nointerface)
no->func_declaration_value()->set_nointerface();
if (!body.empty() && !no->func_declaration_value()->has_imported_body())
no->func_declaration_value()->set_imported_body(body);
return no;
}
......@@ -1395,3 +1398,13 @@ Stream_from_file::do_advance(size_t skip)
this->data_.clear();
}
}
// Class Import_function_body.
// The name of the function we are parsing.
const std::string&
Import_function_body::name() const
{
return this->named_object_->name();
}
......@@ -11,6 +11,7 @@
#include "go-linemap.h"
class Gogo;
class Block;
class Package;
class Type;
class Named_object;
......@@ -464,4 +465,74 @@ class Stream_from_string_ref : public Import::Stream
size_t end_;
};
// Class to manage importing a function body. This is passed around
// to Statements and Expressions. It parses the function into the IR.
class Import_function_body
{
public:
Import_function_body(Gogo* gogo, Location loc, Named_object* named_object,
const std::string& body, size_t off, Block* block,
int indent)
: gogo_(gogo), loc_(loc), named_object_(named_object), body_(body),
off_(off), block_(block), indent_(indent)
{ }
// The IR.
Gogo*
gogo()
{ return this->gogo_; }
// The location to report in an error message.
Location
location() const
{ return this->loc_; }
// A reference to the body we are reading.
const std::string&
body() const
{ return this->body_; }
// The current offset into the body.
size_t
off()
{ return this->off_; }
// Update the offset into the body.
void
set_off(size_t off)
{ this->off_ = off; }
// The current block.
Block*
block()
{ return this->block_; }
// The current indentation.
int
indent() const
{ return this->indent_; }
// The name of the function we are parsing.
const std::string&
name() const;
private:
// The IR.
Gogo* gogo_;
// The location to report in an error message.
Location loc_;
// The function we are parsing.
Named_object* named_object_;
// The exported data we are parsing. Note that this is a reference;
// the body string must laster longer than this object.
const std::string& body_;
// The current offset into body_.
size_t off_;
// Current block.
Block* block_;
// Current expected indentation level.
int indent_;
};
#endif // !defined(GO_IMPORT_H)
......@@ -121,6 +121,14 @@ Statement::determine_types()
this->do_determine_types();
}
// Read a statement from export data.
Statement*
Statement::import_statement(Import_function_body*, Location)
{
go_unreachable();
}
// If this is a thunk statement, return it.
Thunk_statement*
......
......@@ -338,6 +338,10 @@ class Statement
export_statement(Export_function_body* efb)
{ this->do_export_statement(efb); }
// Read a statement from export data.
static Statement*
import_statement(Import_function_body*, Location);
// Return whether this is a block statement.
bool
is_block_statement() const
......
......@@ -9865,7 +9865,9 @@ Named_type::add_method(const std::string& name, Function* function)
go_assert(!this->is_alias_);
if (this->local_methods_ == NULL)
this->local_methods_ = new Bindings(NULL);
return this->local_methods_->add_function(name, NULL, function);
return this->local_methods_->add_function(name,
this->named_object_->package(),
function);
}
// Add a method declaration to this type.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment