Mercurial > hg > CbC > CbC_gcc
diff gcc/go/go-gcc.cc @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/go/go-gcc.cc Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/go/go-gcc.cc Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ // go-gcc.cc -- Go frontend to gcc IR. -// Copyright (C) 2011-2017 Free Software Foundation, Inc. +// Copyright (C) 2011-2018 Free Software Foundation, Inc. // Contributed by Ian Lance Taylor, Google. // This file is part of GCC. @@ -276,7 +276,7 @@ { return this->make_expression(null_pointer_node); } Bexpression* - var_expression(Bvariable* var, Varexpr_context, Location); + var_expression(Bvariable* var, Location); Bexpression* indirect_expression(Btype*, Bexpression* expr, bool known_valid, Location); @@ -352,9 +352,6 @@ const std::vector<Bexpression*>& args, Bexpression* static_chain, Location); - Bexpression* - stack_allocation_expression(int64_t size, Location); - // Statements. Bstatement* @@ -426,7 +423,7 @@ global_variable_set_init(Bvariable*, Bexpression*); Bvariable* - local_variable(Bfunction*, const std::string&, Btype*, bool, + local_variable(Bfunction*, const std::string&, Btype*, Bvariable*, bool, Location); Bvariable* @@ -486,7 +483,8 @@ Bfunction* function(Btype* fntype, const std::string& name, const std::string& asm_name, bool is_visible, bool is_declaration, bool is_inlinable, - bool disable_split_stack, bool in_unique_section, Location); + bool disable_split_stack, bool does_not_return, + bool in_unique_section, Location); Bstatement* function_defer_statement(Bfunction* function, Bexpression* undefer, @@ -540,6 +538,9 @@ tree non_zero_size_type(tree); + tree + convert_tree(tree, tree, Location); + private: void define_builtin(built_in_function bcode, const char* name, const char* libname, @@ -632,7 +633,7 @@ NULL_TREE); tree math_function_type_long = build_function_type_list(long_double_type_node, long_double_type_node, - long_double_type_node, NULL_TREE); + NULL_TREE); tree math_function_type_two = build_function_type_list(double_type_node, double_type_node, double_type_node, @@ -760,6 +761,12 @@ const_ptr_type_node, NULL_TREE), false, false); + + // The compiler uses __builtin_unreachable for cases that can not + // occur. + this->define_builtin(BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL, + build_function_type(void_type_node, void_list_node), + true, true); } // Get an unnamed integer type. @@ -952,6 +959,13 @@ } TYPE_FIELDS(fill_tree) = field_trees; layout_type(fill_tree); + + // Because Go permits converting between named struct types and + // equivalent struct types, for which we use VIEW_CONVERT_EXPR, and + // because we don't try to maintain TYPE_CANONICAL for struct types, + // we need to tell the middle-end to use structural equality. + SET_TYPE_STRUCTURAL_EQUALITY(fill_tree); + return fill; } @@ -1086,7 +1100,7 @@ if (TYPE_NAME(t) != NULL_TREE) { // Build the data structure gcc wants to see for a typedef. - tree copy = build_distinct_type_copy(t); + tree copy = build_variant_type_copy(t); TYPE_NAME(copy) = NULL_TREE; DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy; } @@ -1187,6 +1201,8 @@ tree t = btype->get_tree(); if (t == error_mark_node) return 1; + if (t == void_type_node) + return 0; t = TYPE_SIZE_UNIT(t); gcc_assert(tree_fits_uhwi_p (t)); unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW(t); @@ -1256,7 +1272,7 @@ // An expression that references a variable. Bexpression* -Gcc_backend::var_expression(Bvariable* var, Varexpr_context, Location location) +Gcc_backend::var_expression(Bvariable* var, Location location) { tree ret = var->get_tree(location); if (ret == error_mark_node) @@ -1456,7 +1472,8 @@ return this->error_expression(); tree ret; - if (this->type_size(type) == 0) + if (this->type_size(type) == 0 + || TREE_TYPE(expr_tree) == void_type_node) { // Do not convert zero-sized types. ret = expr_tree; @@ -1778,8 +1795,7 @@ constructor_elt empty = {NULL, NULL}; constructor_elt* elt = init->quick_push(empty); elt->index = field; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - val); + elt->value = this->convert_tree(TREE_TYPE(field), val, location); if (!TREE_CONSTANT(elt->value)) is_constant = false; } @@ -1885,9 +1901,18 @@ || index_tree == error_mark_node) return this->error_expression(); - tree ret = build4_loc(location.gcc_location(), ARRAY_REF, - TREE_TYPE(TREE_TYPE(array_tree)), array_tree, - index_tree, NULL_TREE, NULL_TREE); + // A function call that returns a zero sized object will have been + // changed to return void. If we see void here, assume we are + // dealing with a zero sized type and just evaluate the operands. + tree ret; + if (TREE_TYPE(array_tree) != void_type_node) + ret = build4_loc(location.gcc_location(), ARRAY_REF, + TREE_TYPE(TREE_TYPE(array_tree)), array_tree, + index_tree, NULL_TREE, NULL_TREE); + else + ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, + void_type_node, array_tree, index_tree); + return this->make_expression(ret); } @@ -1923,8 +1948,8 @@ tree excess_type = NULL_TREE; if (optimize && TREE_CODE(fndecl) == FUNCTION_DECL - && DECL_IS_BUILTIN(fndecl) - && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL + && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL) + && DECL_IS_BUILTIN (fndecl) && nargs > 0 && ((SCALAR_FLOAT_TYPE_P(rettype) && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0]))) @@ -1971,20 +1996,6 @@ return this->make_expression(ret); } -// Return an expression that allocates SIZE bytes on the stack. - -Bexpression* -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* @@ -2011,6 +2022,7 @@ // initializer. Such initializations don't mean anything anyhow. if (int_size_in_bytes(TREE_TYPE(var_tree)) != 0 && init_tree != NULL_TREE + && TREE_TYPE(init_tree) != void_type_node && int_size_in_bytes(TREE_TYPE(init_tree)) != 0) { DECL_INITIAL(var_tree) = init_tree; @@ -2043,34 +2055,14 @@ // expression; avoid crashes here by avoiding assignments of // zero-sized expressions. Such assignments don't really mean // anything anyhow. - if (int_size_in_bytes(TREE_TYPE(lhs_tree)) == 0 + if (TREE_TYPE(lhs_tree) == void_type_node + || int_size_in_bytes(TREE_TYPE(lhs_tree)) == 0 + || TREE_TYPE(rhs_tree) == void_type_node || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) 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 - // not confuse the middle-end. - if (TREE_TYPE(lhs_tree) != TREE_TYPE(rhs_tree)) - { - tree lhs_type_tree = TREE_TYPE(lhs_tree); - gcc_assert(TREE_CODE(lhs_type_tree) == TREE_CODE(TREE_TYPE(rhs_tree))); - if (POINTER_TYPE_P(lhs_type_tree) - || INTEGRAL_TYPE_P(lhs_type_tree) - || SCALAR_FLOAT_TYPE_P(lhs_type_tree) - || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) - rhs_tree = fold_convert_loc(location.gcc_location(), lhs_type_tree, - rhs_tree); - else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE - || TREE_CODE(lhs_type_tree) == ARRAY_TYPE) - { - gcc_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); - rhs_tree = fold_build1_loc(location.gcc_location(), - VIEW_CONVERT_EXPR, - lhs_type_tree, rhs_tree); - } - } + rhs_tree = this->convert_tree(TREE_TYPE(lhs_tree), rhs_tree, location); return this->make_statement(fold_build2_loc(location.gcc_location(), MODIFY_EXPR, @@ -2289,8 +2281,8 @@ tree tv = value->get_tree(); if (tv == error_mark_node) return this->error_statement(); - tree t = build3_loc(switch_location.gcc_location(), SWITCH_EXPR, - NULL_TREE, tv, stmt_list, NULL_TREE); + tree t = build2_loc(switch_location.gcc_location(), SWITCH_EXPR, + NULL_TREE, tv, stmt_list); return this->make_statement(t); } @@ -2500,6 +2492,43 @@ gcc_unreachable(); } +// Convert EXPR_TREE to TYPE_TREE. Sometimes the same unnamed Go type +// can be created multiple times and thus have multiple tree +// representations. Make sure this does not confuse the middle-end. + +tree +Gcc_backend::convert_tree(tree type_tree, tree expr_tree, Location location) +{ + if (type_tree == TREE_TYPE(expr_tree)) + return expr_tree; + + if (type_tree == error_mark_node + || expr_tree == error_mark_node + || TREE_TYPE(expr_tree) == error_mark_node) + return error_mark_node; + + gcc_assert(TREE_CODE(type_tree) == TREE_CODE(TREE_TYPE(expr_tree))); + if (POINTER_TYPE_P(type_tree) + || INTEGRAL_TYPE_P(type_tree) + || SCALAR_FLOAT_TYPE_P(type_tree) + || COMPLEX_FLOAT_TYPE_P(type_tree)) + return fold_convert_loc(location.gcc_location(), type_tree, expr_tree); + else if (TREE_CODE(type_tree) == RECORD_TYPE + || TREE_CODE(type_tree) == ARRAY_TYPE) + { + gcc_assert(int_size_in_bytes(type_tree) + == int_size_in_bytes(TREE_TYPE(expr_tree))); + if (TYPE_MAIN_VARIANT(type_tree) + == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree))) + return fold_build1_loc(location.gcc_location(), NOP_EXPR, + type_tree, expr_tree); + return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, + type_tree, expr_tree); + } + + gcc_unreachable(); +} + // Make a global variable. Bvariable* @@ -2577,8 +2606,8 @@ Bvariable* Gcc_backend::local_variable(Bfunction* function, const std::string& name, - Btype* btype, bool is_address_taken, - Location location) + Btype* btype, Bvariable* decl_var, + bool is_address_taken, Location location) { tree type_tree = btype->get_tree(); if (type_tree == error_mark_node) @@ -2590,6 +2619,11 @@ TREE_USED(decl) = 1; if (is_address_taken) TREE_ADDRESSABLE(decl) = 1; + if (decl_var != NULL) + { + DECL_HAS_VALUE_EXPR_P(decl) = 1; + SET_DECL_VALUE_EXPR(decl, decl_var->get_decl()); + } go_preserve_from_gc(decl); return new Bvariable(decl); } @@ -2704,9 +2738,10 @@ BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree); } - if (this->type_size(btype) != 0 && init_tree != NULL_TREE) - DECL_INITIAL(var) = fold_convert_loc(location.gcc_location(), type_tree, - init_tree); + if (this->type_size(btype) != 0 + && init_tree != NULL_TREE + && TREE_TYPE(init_tree) != void_type_node) + DECL_INITIAL(var) = this->convert_tree(type_tree, init_tree, location); if (is_address_taken) TREE_ADDRESSABLE(var) = 1; @@ -2715,9 +2750,11 @@ DECL_EXPR, void_type_node, var)); - // Don't initialize VAR with BINIT, but still evaluate BINIT for - // its side effects. - if (this->type_size(btype) == 0 && init_tree != NULL_TREE) + // For a zero sized type, don't initialize VAR with BINIT, but still + // evaluate BINIT for its side effects. + if (init_tree != NULL_TREE + && (this->type_size(btype) == 0 + || TREE_TYPE(init_tree) == void_type_node)) *pstatement = this->compound_statement(this->expression_statement(function, binit), *pstatement); @@ -3012,8 +3049,8 @@ Gcc_backend::function(Btype* fntype, const std::string& name, const std::string& asm_name, bool is_visible, bool is_declaration, bool is_inlinable, - bool disable_split_stack, bool in_unique_section, - Location location) + bool disable_split_stack, bool does_not_return, + bool in_unique_section, Location location) { tree functype = fntype->get_tree(); if (functype != error_mark_node) @@ -3049,6 +3086,8 @@ tree attr = get_identifier ("no_split_stack"); DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE); } + if (does_not_return) + TREE_THIS_VOLATILE(decl) = 1; if (in_unique_section) resolve_unique_section(decl, 0, 1);