diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-05-02 14:43:35 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-05-02 14:43:35 +0000 |
commit | 34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch) | |
tree | d503eaf41d085669d1481bb46ec038bc866fece6 /gcc/go/go-gcc.cc | |
parent | f733cf303bcdc952c92b81dd62199a40a1f555ec (diff) | |
download | gcc-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.cc | 191 |
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; |