summaryrefslogtreecommitdiff
path: root/gcc/go/go-gcc.cc
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
commit34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch)
treed503eaf41d085669d1481bb46ec038bc866fece6 /gcc/go/go-gcc.cc
parentf733cf303bcdc952c92b81dd62199a40a1f555ec (diff)
downloadgcc-tarball-master.tar.gz
gcc-7.1.0gcc-7.1.0
Diffstat (limited to 'gcc/go/go-gcc.cc')
-rw-r--r--gcc/go/go-gcc.cc191
1 files changed, 137 insertions, 54 deletions
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 2793bb6090..62baa91fab 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -1,5 +1,5 @@
// go-gcc.cc -- Go frontend to gcc IR.
-// Copyright (C) 2011-2016 Free Software Foundation, Inc.
+// Copyright (C) 2011-2017 Free Software Foundation, Inc.
// Contributed by Ian Lance Taylor, Google.
// This file is part of GCC.
@@ -43,6 +43,7 @@
#include "builtins.h"
#include "go-c.h"
+#include "go-gcc.h"
#include "gogo.h"
#include "backend.h"
@@ -275,7 +276,7 @@ class Gcc_backend : public Backend
{ return this->make_expression(null_pointer_node); }
Bexpression*
- var_expression(Bvariable* var, Location);
+ var_expression(Bvariable* var, Varexpr_context, Location);
Bexpression*
indirect_expression(Btype*, Bexpression* expr, bool known_valid, Location);
@@ -324,8 +325,8 @@ class Gcc_backend : public Backend
compound_expression(Bstatement*, Bexpression*, Location);
Bexpression*
- conditional_expression(Btype*, Bexpression*, Bexpression*, Bexpression*,
- Location);
+ conditional_expression(Bfunction*, Btype*, Bexpression*, Bexpression*,
+ Bexpression*, Location);
Bexpression*
unary_expression(Operator, Bexpression*, Location);
@@ -360,21 +361,22 @@ class Gcc_backend : public Backend
{ return this->make_statement(error_mark_node); }
Bstatement*
- expression_statement(Bexpression*);
+ expression_statement(Bfunction*, Bexpression*);
Bstatement*
- init_statement(Bvariable* var, Bexpression* init);
+ init_statement(Bfunction*, Bvariable* var, Bexpression* init);
Bstatement*
- assignment_statement(Bexpression* lhs, Bexpression* rhs, Location);
+ assignment_statement(Bfunction*, Bexpression* lhs, Bexpression* rhs,
+ Location);
Bstatement*
return_statement(Bfunction*, const std::vector<Bexpression*>&,
Location);
Bstatement*
- if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block,
- Location);
+ if_statement(Bfunction*, Bexpression* condition, Bblock* then_block,
+ Bblock* else_block, Location);
Bstatement*
switch_statement(Bfunction* function, Bexpression* value,
@@ -411,9 +413,8 @@ class Gcc_backend : public Backend
{ return new Bvariable(error_mark_node); }
Bvariable*
- global_variable(const std::string& package_name,
- const std::string& pkgpath,
- const std::string& name,
+ global_variable(const std::string& var_name,
+ const std::string& asm_name,
Btype* btype,
bool is_external,
bool is_hidden,
@@ -439,25 +440,27 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
- implicit_variable(const std::string&, Btype*, bool, bool, bool,
- int64_t);
+ implicit_variable(const std::string&, const std::string&, Btype*,
+ bool, bool, bool, int64_t);
void
implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
bool, bool, bool, Bexpression*);
Bvariable*
- implicit_variable_reference(const std::string&, Btype*);
+ implicit_variable_reference(const std::string&, const std::string&, Btype*);
Bvariable*
- immutable_struct(const std::string&, bool, bool, Btype*, Location);
+ immutable_struct(const std::string&, const std::string&,
+ bool, bool, Btype*, Location);
void
immutable_struct_set_init(Bvariable*, const std::string&, bool, bool, Btype*,
Location, Bexpression*);
Bvariable*
- immutable_struct_reference(const std::string&, Btype*, Location);
+ immutable_struct_reference(const std::string&, const std::string&,
+ Btype*, Location);
// Labels.
@@ -541,7 +544,7 @@ private:
std::map<std::string, Bfunction*> builtin_functions_;
};
-// A helper function.
+// A helper function to create a GCC identifier from a C++ string.
static inline tree
get_identifier_from_string(const std::string& str)
@@ -555,25 +558,25 @@ Gcc_backend::Gcc_backend()
{
/* We need to define the fetch_and_add functions, since we use them
for ++ and --. */
- tree t = this->integer_type(BITS_PER_UNIT, 1)->get_tree();
+ tree t = this->integer_type(true, BITS_PER_UNIT)->get_tree();
tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_fetch_and_add_1",
NULL, build_function_type_list(t, p, t, NULL_TREE),
false, false);
- t = this->integer_type(BITS_PER_UNIT * 2, 1)->get_tree();
+ t = this->integer_type(true, BITS_PER_UNIT * 2)->get_tree();
p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_fetch_and_add_2",
NULL, build_function_type_list(t, p, t, NULL_TREE),
false, false);
- t = this->integer_type(BITS_PER_UNIT * 4, 1)->get_tree();
+ t = this->integer_type(true, BITS_PER_UNIT * 4)->get_tree();
p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_fetch_and_add_4",
NULL, build_function_type_list(t, p, t, NULL_TREE),
false, false);
- t = this->integer_type(BITS_PER_UNIT * 8, 1)->get_tree();
+ t = this->integer_type(true, BITS_PER_UNIT * 8)->get_tree();
p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_fetch_and_add_8",
NULL, build_function_type_list(t, p, t, NULL_TREE),
@@ -596,6 +599,28 @@ Gcc_backend::Gcc_backend()
NULL_TREE),
false, false);
+ // Used by runtime/internal/sys.
+ this->define_builtin(BUILT_IN_CTZ, "__builtin_ctz", "ctz",
+ build_function_type_list(integer_type_node,
+ unsigned_type_node,
+ NULL_TREE),
+ true, false);
+ this->define_builtin(BUILT_IN_CTZLL, "__builtin_ctzll", "ctzll",
+ build_function_type_list(integer_type_node,
+ long_long_unsigned_type_node,
+ NULL_TREE),
+ true, false);
+ this->define_builtin(BUILT_IN_BSWAP32, "__builtin_bswap32", "bswap32",
+ build_function_type_list(uint32_type_node,
+ uint32_type_node,
+ NULL_TREE),
+ true, false);
+ this->define_builtin(BUILT_IN_BSWAP64, "__builtin_bswap64", "bswap64",
+ build_function_type_list(uint64_type_node,
+ uint64_type_node,
+ NULL_TREE),
+ true, false);
+
// We provide some functions for the math library.
tree math_function_type = build_function_type_list(double_type_node,
double_type_node,
@@ -700,11 +725,21 @@ Gcc_backend::Gcc_backend()
math_function_type_long, true, false);
// We use __builtin_return_address in the thunk we build for
- // functions which call recover.
+ // functions which call recover, and for runtime.getcallerpc.
+ t = build_function_type_list(ptr_type_node, unsigned_type_node, NULL_TREE);
this->define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address",
- NULL,
+ NULL, t, false, false);
+
+ // The runtime calls __builtin_frame_address for runtime.getcallersp.
+ this->define_builtin(BUILT_IN_FRAME_ADDRESS, "__builtin_frame_address",
+ NULL, t, false, false);
+
+ // The runtime calls __builtin_extract_return_addr when recording
+ // the address to which a function returns.
+ this->define_builtin(BUILT_IN_EXTRACT_RETURN_ADDR,
+ "__builtin_extract_return_addr", NULL,
build_function_type_list(ptr_type_node,
- unsigned_type_node,
+ ptr_type_node,
NULL_TREE),
false, false);
@@ -857,6 +892,14 @@ Gcc_backend::function_type(const Btyped_identifier& receiver,
if (result == error_mark_node)
return this->error_type();
+ // The libffi library can not represent a zero-sized object. To
+ // avoid causing confusion on 32-bit SPARC, we treat a function that
+ // returns a zero-sized value as returning void. That should do no
+ // harm since there is no actual value to be returned. See
+ // https://gcc.gnu.org/PR72814 for details.
+ if (result != void_type_node && int_size_in_bytes(result) == 0)
+ result = void_type_node;
+
tree fntype = build_function_type(result, args);
if (fntype == error_mark_node)
return this->error_type();
@@ -1201,7 +1244,7 @@ Gcc_backend::zero_expression(Btype* btype)
// An expression that references a variable.
Bexpression*
-Gcc_backend::var_expression(Bvariable* var, Location location)
+Gcc_backend::var_expression(Bvariable* var, Varexpr_context, Location location)
{
tree ret = var->get_tree(location);
if (ret == error_mark_node)
@@ -1503,7 +1546,8 @@ Gcc_backend::compound_expression(Bstatement* bstat, Bexpression* bexpr,
// ELSE_EXPR otherwise.
Bexpression*
-Gcc_backend::conditional_expression(Btype* btype, Bexpression* condition,
+Gcc_backend::conditional_expression(Bfunction*, Btype* btype,
+ Bexpression* condition,
Bexpression* then_expr,
Bexpression* else_expr, Location location)
{
@@ -1921,13 +1965,16 @@ Gcc_backend::stack_allocation_expression(int64_t size, Location location)
tree alloca = builtin_decl_explicit(BUILT_IN_ALLOCA);
tree size_tree = build_int_cst(integer_type_node, size);
tree ret = build_call_expr_loc(location.gcc_location(), alloca, 1, size_tree);
+ tree memset = builtin_decl_explicit(BUILT_IN_MEMSET);
+ ret = build_call_expr_loc(location.gcc_location(), memset, 3,
+ ret, integer_zero_node, size_tree);
return this->make_expression(ret);
}
// An expression as a statement.
Bstatement*
-Gcc_backend::expression_statement(Bexpression* expr)
+Gcc_backend::expression_statement(Bfunction*, Bexpression* expr)
{
return this->make_statement(expr->get_tree());
}
@@ -1935,7 +1982,7 @@ Gcc_backend::expression_statement(Bexpression* expr)
// Variable initialization.
Bstatement*
-Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
+Gcc_backend::init_statement(Bfunction*, Bvariable* var, Bexpression* init)
{
tree var_tree = var->get_decl();
tree init_tree = init->get_tree();
@@ -1968,8 +2015,8 @@ Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
// Assignment.
Bstatement*
-Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
- Location location)
+Gcc_backend::assignment_statement(Bfunction* bfn, Bexpression* lhs,
+ Bexpression* rhs, Location location)
{
tree lhs_tree = lhs->get_tree();
tree rhs_tree = rhs->get_tree();
@@ -1984,8 +2031,8 @@ Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
// anything anyhow.
if (int_size_in_bytes(TREE_TYPE(lhs_tree)) == 0
|| int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0)
- return this->compound_statement(this->expression_statement(lhs),
- this->expression_statement(rhs));
+ return this->compound_statement(this->expression_statement(bfn, lhs),
+ this->expression_statement(bfn, rhs));
// Sometimes the same unnamed Go type can be created multiple times
// and thus have multiple tree representations. Make sure this does
@@ -2031,6 +2078,28 @@ Gcc_backend::return_statement(Bfunction* bfunction,
if (result == error_mark_node)
return this->error_statement();
+ // If the result size is zero bytes, we have set the function type
+ // to have a result type of void, so don't return anything.
+ // See the function_type method.
+ tree res_type = TREE_TYPE(result);
+ if (res_type == void_type_node || int_size_in_bytes(res_type) == 0)
+ {
+ tree stmt_list = NULL_TREE;
+ for (std::vector<Bexpression*>::const_iterator p = vals.begin();
+ p != vals.end();
+ p++)
+ {
+ tree val = (*p)->get_tree();
+ if (val == error_mark_node)
+ return this->error_statement();
+ append_to_statement_list(val, &stmt_list);
+ }
+ tree ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR,
+ void_type_node, NULL_TREE);
+ append_to_statement_list(ret, &stmt_list);
+ return this->make_statement(stmt_list);
+ }
+
tree ret;
if (vals.empty())
ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node,
@@ -2128,8 +2197,9 @@ Gcc_backend::exception_handler_statement(Bstatement* bstat,
// If.
Bstatement*
-Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block,
- Bblock* else_block, Location location)
+Gcc_backend::if_statement(Bfunction*, Bexpression* condition,
+ Bblock* then_block, Bblock* else_block,
+ Location location)
{
tree cond_tree = condition->get_tree();
tree then_tree = then_block->get_tree();
@@ -2419,9 +2489,8 @@ Gcc_backend::non_zero_size_type(tree type)
// Make a global variable.
Bvariable*
-Gcc_backend::global_variable(const std::string& package_name,
- const std::string& pkgpath,
- const std::string& name,
+Gcc_backend::global_variable(const std::string& var_name,
+ const std::string& asm_name,
Btype* btype,
bool is_external,
bool is_hidden,
@@ -2437,9 +2506,6 @@ Gcc_backend::global_variable(const std::string& package_name,
if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0)
type_tree = this->non_zero_size_type(type_tree);
- std::string var_name(package_name);
- var_name.push_back('.');
- var_name.append(name);
tree decl = build_decl(location.gcc_location(), VAR_DECL,
get_identifier_from_string(var_name),
type_tree);
@@ -2450,12 +2516,13 @@ Gcc_backend::global_variable(const std::string& package_name,
if (!is_hidden)
{
TREE_PUBLIC(decl) = 1;
-
- std::string asm_name(pkgpath);
- asm_name.push_back('.');
- asm_name.append(name);
SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
}
+ else
+ {
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+ }
+
TREE_USED(decl) = 1;
if (in_unique_section)
@@ -2637,8 +2704,9 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
// Don't initialize VAR with BINIT, but still evaluate BINIT for
// its side effects.
if (this->type_size(btype) == 0 && init_tree != NULL_TREE)
- *pstatement = this->compound_statement(this->expression_statement(binit),
- *pstatement);
+ *pstatement =
+ this->compound_statement(this->expression_statement(function, binit),
+ *pstatement);
return new Bvariable(var);
}
@@ -2647,8 +2715,9 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
// generating GC root variables and storing the values of a slice initializer.
Bvariable*
-Gcc_backend::implicit_variable(const std::string& name, Btype* type,
- bool is_hidden, bool is_constant,
+Gcc_backend::implicit_variable(const std::string& name,
+ const std::string& asm_name,
+ Btype* type, bool is_hidden, bool is_constant,
bool is_common, int64_t alignment)
{
tree type_tree = type->get_tree();
@@ -2687,9 +2756,11 @@ Gcc_backend::implicit_variable(const std::string& name, Btype* type,
}
if (alignment != 0)
{
- DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
+ SET_DECL_ALIGN(decl, alignment * BITS_PER_UNIT);
DECL_USER_ALIGN(decl) = 1;
}
+ if (! asm_name.empty())
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
go_preserve_from_gc(decl);
return new Bvariable(decl);
@@ -2730,7 +2801,9 @@ Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
// Return a reference to an implicit variable defined in another package.
Bvariable*
-Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
+Gcc_backend::implicit_variable_reference(const std::string& name,
+ const std::string& asm_name,
+ Btype* btype)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
@@ -2742,6 +2815,8 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
TREE_PUBLIC(decl) = 1;
TREE_STATIC(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
+ if (! asm_name.empty())
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
@@ -2749,7 +2824,9 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
// Create a named immutable initialized data structure.
Bvariable*
-Gcc_backend::immutable_struct(const std::string& name, bool is_hidden,
+Gcc_backend::immutable_struct(const std::string& name,
+ const std::string& asm_name,
+ bool is_hidden,
bool is_common, Btype* btype, Location location)
{
tree type_tree = btype->get_tree();
@@ -2766,6 +2843,8 @@ Gcc_backend::immutable_struct(const std::string& name, bool is_hidden,
DECL_ARTIFICIAL(decl) = 1;
if (!is_hidden)
TREE_PUBLIC(decl) = 1;
+ if (! asm_name.empty())
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
// When the initializer for one immutable_struct refers to another,
// it needs to know the visibility of the referenced struct so that
@@ -2825,7 +2904,9 @@ Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&,
// defined in another package.
Bvariable*
-Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype,
+Gcc_backend::immutable_struct_reference(const std::string& name,
+ const std::string& asm_name,
+ Btype* btype,
Location location)
{
tree type_tree = btype->get_tree();
@@ -2840,6 +2921,8 @@ Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype,
DECL_ARTIFICIAL(decl) = 1;
TREE_PUBLIC(decl) = 1;
DECL_EXTERNAL(decl) = 1;
+ if (! asm_name.empty())
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
@@ -2929,7 +3012,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
return this->error_function();
tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype);
- if (!asm_name.empty())
+ if (! asm_name.empty())
SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
if (is_visible)
TREE_PUBLIC(decl) = 1;