// go-gcc.cc -- Go frontend to gcc IR. // Copyright (C) 2011 Free Software Foundation, Inc. // Contributed by Ian Lance Taylor, Google. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "go-system.h" // This has to be included outside of extern "C", so we have to // include it here before tree.h includes it later. #include #ifndef ENABLE_BUILD_WITH_CXX extern "C" { #endif #include "tree.h" #include "tree-iterator.h" #include "gimple.h" #ifndef ENABLE_BUILD_WITH_CXX } #endif #include "gogo.h" #include "backend.h" // A class wrapping a tree. class Gcc_tree { public: Gcc_tree(tree t) : t_(t) { } tree get_tree() { return this->t_; } private: tree t_; }; // In gcc, types, expressions, and statements are all trees. class Btype : public Gcc_tree { public: Btype(tree t) : Gcc_tree(t) { } }; class Bexpression : public Gcc_tree { public: Bexpression(tree t) : Gcc_tree(t) { } }; class Bstatement : public Gcc_tree { public: Bstatement(tree t) : Gcc_tree(t) { } }; class Bfunction : public Gcc_tree { public: Bfunction(tree t) : Gcc_tree(t) { } }; class Blabel : public Gcc_tree { public: Blabel(tree t) : Gcc_tree(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 // frontend proper class methods of these classes to generate the // backend representation. class Gcc_backend : public Backend { public: // Types. Btype* error_type() { gcc_unreachable(); } Btype* void_type() { gcc_unreachable(); } Btype* bool_type() { gcc_unreachable(); } Btype* integer_type(bool /* is_unsigned */, int /* bits */) { gcc_unreachable(); } Btype* float_type(int /* bits */) { gcc_unreachable(); } Btype* string_type() { gcc_unreachable(); } Btype* function_type(const Function_type*, Btype* /* receiver */, const Btypes* /* parameters */, const Btypes* /* results */) { gcc_unreachable(); } Btype* struct_type(const Struct_type*, const Btypes* /* field_types */) { gcc_unreachable(); } Btype* array_type(const Btype* /* element_type */, const Bexpression* /* length */) { gcc_unreachable(); } Btype* slice_type(const Btype* /* element_type */) { gcc_unreachable(); } Btype* map_type(const Btype* /* key_type */, const Btype* /* value_type */, source_location) { gcc_unreachable(); } Btype* channel_type(const Btype* /* element_type */) { gcc_unreachable(); } Btype* interface_type(const Interface_type*, const Btypes* /* method_types */) { gcc_unreachable(); } // Statements. Bstatement* expression_statement(Bexpression*); Bstatement* assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location); Bstatement* return_statement(Bfunction*, const std::vector&, source_location); Bstatement* if_statement(Bexpression* condition, Bstatement* then_block, Bstatement* else_block, source_location); Bstatement* switch_statement(Bexpression* value, const std::vector >& cases, const std::vector& statements, source_location); Bstatement* statement_list(const std::vector&); // Labels. Blabel* label(Bfunction*, const std::string& name, source_location); Bstatement* label_definition_statement(Blabel*); Bstatement* goto_statement(Blabel*, source_location); Bexpression* label_address(Blabel*, source_location); private: // Make a Bexpression from a tree. Bexpression* make_expression(tree t) { return new Bexpression(t); } // Make a Bstatement from a tree. Bstatement* make_statement(tree t) { return new Bstatement(t); } }; // A helper function. static inline tree get_identifier_from_string(const std::string& str) { return get_identifier_with_length(str.data(), str.length()); } // An expression as a statement. Bstatement* Gcc_backend::expression_statement(Bexpression* expr) { return this->make_statement(expr->get_tree()); } // Assignment. Bstatement* Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location location) { tree lhs_tree = lhs->get_tree(); tree rhs_tree = rhs->get_tree(); if (lhs_tree == error_mark_node || rhs_tree == error_mark_node) return this->make_statement(error_mark_node); return this->make_statement(fold_build2_loc(location, MODIFY_EXPR, void_type_node, lhs_tree, rhs_tree)); } // Return. Bstatement* Gcc_backend::return_statement(Bfunction* bfunction, const std::vector& vals, source_location location) { tree fntree = bfunction->get_tree(); if (fntree == error_mark_node) return this->make_statement(error_mark_node); tree result = DECL_RESULT(fntree); if (result == error_mark_node) return this->make_statement(error_mark_node); tree ret; if (vals.empty()) ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, NULL_TREE); else if (vals.size() == 1) { tree val = vals.front()->get_tree(); if (val == error_mark_node) return this->make_statement(error_mark_node); tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, result, vals.front()->get_tree()); ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, set); } else { // To return multiple values, copy the values into a temporary // variable of the right structure type, and then assign the // temporary variable to the DECL_RESULT in the return // statement. tree stmt_list = NULL_TREE; tree rettype = TREE_TYPE(result); tree rettmp = create_tmp_var(rettype, "RESULT"); tree field = TYPE_FIELDS(rettype); for (std::vector::const_iterator p = vals.begin(); p != vals.end(); p++, field = DECL_CHAIN(field)) { gcc_assert(field != NULL_TREE); tree ref = fold_build3_loc(location, COMPONENT_REF, TREE_TYPE(field), rettmp, field, NULL_TREE); tree val = (*p)->get_tree(); if (val == error_mark_node) return this->make_statement(error_mark_node); tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, ref, (*p)->get_tree()); append_to_statement_list(set, &stmt_list); } gcc_assert(field == NULL_TREE); tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, result, rettmp); tree ret_expr = fold_build1_loc(location, RETURN_EXPR, void_type_node, set); append_to_statement_list(ret_expr, &stmt_list); ret = stmt_list; } return this->make_statement(ret); } // If. Bstatement* Gcc_backend::if_statement(Bexpression* condition, Bstatement* then_block, Bstatement* else_block, source_location location) { tree cond_tree = condition->get_tree(); tree then_tree = then_block->get_tree(); tree else_tree = else_block == NULL ? NULL_TREE : else_block->get_tree(); if (cond_tree == error_mark_node || then_tree == error_mark_node || else_tree == error_mark_node) return this->make_statement(error_mark_node); tree ret = build3_loc(location, COND_EXPR, void_type_node, cond_tree, then_tree, else_tree); return this->make_statement(ret); } // Switch. Bstatement* Gcc_backend::switch_statement( Bexpression* value, const std::vector >& cases, const std::vector& statements, source_location switch_location) { gcc_assert(cases.size() == statements.size()); tree stmt_list = NULL_TREE; std::vector >::const_iterator pc = cases.begin(); for (std::vector::const_iterator ps = statements.begin(); ps != statements.end(); ++ps, ++pc) { if (pc->empty()) { source_location loc = (*ps != NULL ? EXPR_LOCATION((*ps)->get_tree()) : UNKNOWN_LOCATION); tree label = create_artificial_label(loc); tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE, label); append_to_statement_list(c, &stmt_list); } else { for (std::vector::const_iterator pcv = pc->begin(); pcv != pc->end(); ++pcv) { tree t = (*pcv)->get_tree(); if (t == error_mark_node) return this->make_statement(error_mark_node); source_location loc = EXPR_LOCATION(t); tree label = create_artificial_label(loc); tree c = build3_loc(loc, CASE_LABEL_EXPR, void_type_node, (*pcv)->get_tree(), NULL_TREE, label); append_to_statement_list(c, &stmt_list); } } if (*ps != NULL) { tree t = (*ps)->get_tree(); if (t == error_mark_node) return this->make_statement(error_mark_node); append_to_statement_list(t, &stmt_list); } } tree tv = value->get_tree(); if (tv == error_mark_node) return this->make_statement(error_mark_node); tree t = build3_loc(switch_location, SWITCH_EXPR, void_type_node, tv, stmt_list, NULL_TREE); return this->make_statement(t); } // List of statements. Bstatement* Gcc_backend::statement_list(const std::vector& statements) { tree stmt_list = NULL_TREE; for (std::vector::const_iterator p = statements.begin(); p != statements.end(); ++p) { tree t = (*p)->get_tree(); if (t == error_mark_node) return this->make_statement(error_mark_node); append_to_statement_list(t, &stmt_list); } return this->make_statement(stmt_list); } // Make a label. Blabel* Gcc_backend::label(Bfunction* function, const std::string& name, source_location location) { tree decl; if (name.empty()) decl = create_artificial_label(location); else { tree id = get_identifier_from_string(name); decl = build_decl(location, LABEL_DECL, id, void_type_node); DECL_CONTEXT(decl) = function->get_tree(); } return new Blabel(decl); } // Make a statement which defines a label. Bstatement* Gcc_backend::label_definition_statement(Blabel* label) { tree lab = label->get_tree(); tree ret = fold_build1_loc(DECL_SOURCE_LOCATION(lab), LABEL_EXPR, void_type_node, lab); return this->make_statement(ret); } // Make a goto statement. Bstatement* Gcc_backend::goto_statement(Blabel* label, source_location location) { tree lab = label->get_tree(); tree ret = fold_build1_loc(location, GOTO_EXPR, void_type_node, lab); return this->make_statement(ret); } // Get the address of a label. Bexpression* Gcc_backend::label_address(Blabel* label, source_location location) { tree lab = label->get_tree(); TREE_USED(lab) = 1; TREE_ADDRESSABLE(lab) = 1; tree ret = fold_convert_loc(location, ptr_type_node, build_fold_addr_expr_loc(location, lab)); return this->make_expression(ret); } // The single backend. static Gcc_backend gcc_backend; // Return the backend generator. Backend* go_get_backend() { return &gcc_backend; } // FIXME: Temporary functions while converting to the new backend // interface. Bexpression* tree_to_expr(tree t) { return new Bexpression(t); } Bstatement* tree_to_stat(tree t) { return new Bstatement(t); } Bfunction* tree_to_function(tree t) { return new Bfunction(t); } tree expr_to_tree(Bexpression* be) { return be->get_tree(); } tree stat_to_tree(Bstatement* bs) { return bs->get_tree(); }