On Mon, Dec 21, 2015 at 4:19 PM, Andrew Pinski <pins...@gmail.com> wrote: > On Mon, Dec 21, 2015 at 4:10 PM, Ian Lance Taylor <i...@golang.org> wrote: >> The GNU linker doesn't support a zero-sized global variable that is >> dynamically exported, so gccgo generates those global variables with a >> size of 1 byte. Unfortunately, that means that passing a global >> variable to a function that takes an argument of a zero-sized type >> will actually pass 1 byte, taking up an argument slot, rather than a >> zero-sized argument that should be skipped. This patch fixes the >> problem in the Go frontend -> GCC interface by adding a conversion to >> the real type for any such global variables, and undoing the >> conversion where necessary. Bootstrapped and ran Go testsuite on >> x86_64-pc-linux-gnu. Committed to mainline and gccgo branch. > > VIEW_CONVERT_EXPR on different size types is invalid for GCC's IR. > So this patch cause other issues.
Thanks again. This patch should fix that by taking a somewhat different approach. Instead of a VIEW_CONVERT_EXPR it generates *(orig_type*)&decl. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline and gccgo branch. Ian 2015-12-21 Ian Lance Taylor <i...@google.com> * go-gcc.cc (class Bvariable): Remove Gcc_tree parent class. Add t_ and orig_type_ fields. Add new two parameter constructor. Add get_tree and get_decl methods. (Gcc_backend::var_expression): Pass location to var get_tree. (Gcc_backend::global_variable): Don't add VIEW_CONVERT_EXPR. Use two parameter constructor for Bvariable. (Gcc_backend::global_variable_set_init): Don't remove VIEW_CONVERT_EXPR. Use var get_decl, not get_tree. (Gcc_backend::write_global_definitions): Likewise. (Gcc_backend::init_statement): Call var get_decl, not get_tree. (Gcc_backend::block): Likewise. (Gcc_backend::implicit_variable_set_init): Likewise. (Gcc_backend::immutable_struct_set_init): Likewise. (Gcc_backend::function_set_parameters): Likewise.
Index: go-gcc.cc =================================================================== --- go-gcc.cc (revision 231888) +++ go-gcc.cc (working copy) @@ -109,22 +109,65 @@ class Bblock : public Gcc_tree { } }; -class Bvariable : public Gcc_tree +class Blabel : public Gcc_tree { public: - Bvariable(tree t) + Blabel(tree t) : Gcc_tree(t) { } }; -class Blabel : public Gcc_tree +// Bvariable is a bit more complicated, because of zero-sized types. +// The GNU linker does not permit dynamic variables with zero size. +// When we see such a variable, we generate a version of the type with +// non-zero size. However, when referring to the global variable, we +// want an expression of zero size; otherwise, if, say, the global +// variable is passed to a function, we will be passing a +// non-zero-sized value to a zero-sized value, which can lead to a +// miscompilation. + +class Bvariable { public: - Blabel(tree t) - : Gcc_tree(t) + Bvariable(tree t) + : t_(t), orig_type_(NULL) { } + + Bvariable(tree t, tree orig_type) + : t_(t), orig_type_(orig_type) + { } + + // Get the tree for use as an expression. + tree + get_tree(Location) const; + + // Get the actual decl; + tree + get_decl() const + { return this->t_; } + + private: + tree t_; + tree orig_type_; }; +// Get the tree of a variable for use as an expression. If this is a +// zero-sized global, create an expression that refers to the decl but +// has zero size. +tree +Bvariable::get_tree(Location location) const +{ + if (this->orig_type_ == NULL + || this->t_ == error_mark_node + || TREE_TYPE(this->t_) == this->orig_type_) + return this->t_; + // Return *(orig_type*)&decl. */ + tree t = build_fold_addr_expr_loc(location.gcc_location(), this->t_); + t = fold_build1_loc(location.gcc_location(), NOP_EXPR, + build_pointer_type(this->orig_type_), t); + return build_fold_indirect_ref_loc(location.gcc_location(), t); +} + // This file implements the interface between the Go frontend proper // and the gcc IR. This implements specific instantiations of // abstract classes defined by the Go frontend proper. The Go @@ -1158,9 +1201,9 @@ Gcc_backend::zero_expression(Btype* btyp // An expression that references a variable. Bexpression* -Gcc_backend::var_expression(Bvariable* var, Location) +Gcc_backend::var_expression(Bvariable* var, Location location) { - tree ret = var->get_tree(); + tree ret = var->get_tree(location); if (ret == error_mark_node) return this->error_expression(); return this->make_expression(ret); @@ -1894,7 +1937,7 @@ Gcc_backend::expression_statement(Bexpre Bstatement* Gcc_backend::init_statement(Bvariable* var, Bexpression* init) { - tree var_tree = var->get_tree(); + tree var_tree = var->get_decl(); tree init_tree = init->get_tree(); if (var_tree == error_mark_node || init_tree == error_mark_node) return this->error_statement(); @@ -2264,7 +2307,7 @@ Gcc_backend::block(Bfunction* function, pv != vars.end(); ++pv) { - *pp = (*pv)->get_tree(); + *pp = (*pv)->get_decl(); if (*pp != error_mark_node) pp = &DECL_CHAIN(*pp); } @@ -2420,11 +2463,7 @@ Gcc_backend::global_variable(const std:: go_preserve_from_gc(decl); - if (orig_type_tree != type_tree) - decl = fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, - orig_type_tree, decl); - - return new Bvariable(decl); + return new Bvariable(decl, orig_type_tree); } // Set the initial value of a global variable. @@ -2436,13 +2475,9 @@ Gcc_backend::global_variable_set_init(Bv if (expr_tree == error_mark_node) return; gcc_assert(TREE_CONSTANT(expr_tree)); - tree var_decl = var->get_tree(); + tree var_decl = var->get_decl(); if (var_decl == error_mark_node) return; - // Undo the VIEW_CONVERT_EXPR that may have been added by - // global_variable. - if (TREE_CODE(var_decl) == VIEW_CONVERT_EXPR) - var_decl = TREE_OPERAND(var_decl, 0); DECL_INITIAL(var_decl) = expr_tree; // If this variable goes in a unique section, it may need to go into @@ -2668,7 +2703,7 @@ Gcc_backend::implicit_variable_set_init( Btype*, bool, bool, bool is_common, Bexpression* init) { - tree decl = var->get_tree(); + tree decl = var->get_decl(); tree init_tree; if (init == NULL) init_tree = NULL_TREE; @@ -2762,7 +2797,7 @@ Gcc_backend::immutable_struct_set_init(B bool, bool is_common, Btype*, Location, Bexpression* initializer) { - tree decl = var->get_tree(); + tree decl = var->get_decl(); tree init_tree = initializer->get_tree(); if (decl == error_mark_node || init_tree == error_mark_node) return; @@ -2981,7 +3016,7 @@ Gcc_backend::function_set_parameters(Bfu pv != param_vars.end(); ++pv) { - *pp = (*pv)->get_tree(); + *pp = (*pv)->get_decl(); gcc_assert(*pp != error_mark_node); pp = &DECL_CHAIN(*pp); } @@ -3037,14 +3072,10 @@ Gcc_backend::write_global_definitions( p != variable_decls.end(); ++p) { - if ((*p)->get_tree() != error_mark_node) + tree v = (*p)->get_decl(); + if (v != error_mark_node) { - tree t = (*p)->get_tree(); - // Undo the VIEW_CONVERT_EXPR that may have been added by - // global_variable. - if (TREE_CODE(t) == VIEW_CONVERT_EXPR) - t = TREE_OPERAND(t, 0); - defs[i] = t; + defs[i] = v; go_preserve_from_gc(defs[i]); ++i; }