| // go.cc -- Go frontend main file for gcc. |
| |
| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| #include "go-system.h" |
| |
| #include "go-c.h" |
| #include "go-diagnostics.h" |
| |
| #include "lex.h" |
| #include "parse.h" |
| #include "backend.h" |
| #include "gogo.h" |
| |
| // The data structures we build to represent the file. |
| static Gogo* gogo; |
| |
| // Create the main IR data structure. |
| |
| GO_EXTERN_C |
| void |
| go_create_gogo(const struct go_create_gogo_args* args) |
| { |
| go_assert(::gogo == NULL); |
| ::gogo = new Gogo(args->backend, args->linemap, args->int_type_size, |
| args->pointer_size); |
| |
| if (args->pkgpath != NULL) |
| ::gogo->set_pkgpath(args->pkgpath); |
| else if (args->prefix != NULL) |
| ::gogo->set_prefix(args->prefix); |
| |
| if (args->relative_import_path != NULL) |
| ::gogo->set_relative_import_path(args->relative_import_path); |
| ::gogo->set_check_divide_by_zero(args->check_divide_by_zero); |
| ::gogo->set_check_divide_overflow(args->check_divide_overflow); |
| if (args->compiling_runtime) |
| ::gogo->set_compiling_runtime(args->compiling_runtime); |
| if (args->c_header != NULL) |
| ::gogo->set_c_header(args->c_header); |
| if (args->importcfg != NULL) |
| ::gogo->read_importcfg(args->importcfg); |
| if (args->embedcfg != NULL) |
| ::gogo->read_embedcfg(args->embedcfg); |
| ::gogo->set_debug_escape_level(args->debug_escape_level); |
| if (args->debug_escape_hash != NULL) |
| ::gogo->set_debug_escape_hash(args->debug_escape_hash); |
| ::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold); |
| if (args->debug_optimization) |
| ::gogo->set_debug_optimization(args->debug_optimization); |
| if (args->need_eqtype) |
| ::gogo->set_need_eqtype(args->need_eqtype); |
| } |
| |
| // Parse the input files. |
| |
| GO_EXTERN_C |
| void |
| go_parse_input_files(const char** filenames, unsigned int filename_count, |
| bool only_check_syntax, bool) |
| { |
| go_assert(filename_count > 0); |
| |
| Lex::Linknames all_linknames; |
| for (unsigned int i = 0; i < filename_count; ++i) |
| { |
| if (i > 0) |
| ::gogo->clear_file_scope(); |
| |
| const char* filename = filenames[i]; |
| FILE* file; |
| if (strcmp(filename, "-") == 0) |
| file = stdin; |
| else |
| { |
| file = fopen(filename, "r"); |
| if (file == NULL) |
| go_fatal_error(Linemap::unknown_location(), |
| "cannot open %s: %m", filename); |
| } |
| |
| Lex lexer(filename, file, ::gogo->linemap()); |
| |
| Parse parse(&lexer, ::gogo); |
| parse.program(); |
| |
| if (strcmp(filename, "-") != 0) |
| fclose(file); |
| |
| Lex::Linknames* linknames = lexer.get_and_clear_linknames(); |
| if (linknames != NULL) |
| { |
| if (!::gogo->current_file_imported_unsafe()) |
| { |
| for (Lex::Linknames::const_iterator p = linknames->begin(); |
| p != linknames->end(); |
| ++p) |
| go_error_at(p->second.loc, |
| ("%<//go:linkname%> only allowed in Go files that " |
| "import \"unsafe\"")); |
| } |
| all_linknames.insert(linknames->begin(), linknames->end()); |
| } |
| } |
| |
| ::gogo->clear_file_scope(); |
| |
| // If the global predeclared names are referenced but not defined, |
| // define them now. |
| ::gogo->define_global_names(); |
| |
| // Apply any go:linkname directives. |
| for (Lex::Linknames::const_iterator p = all_linknames.begin(); |
| p != all_linknames.end(); |
| ++p) |
| ::gogo->add_linkname(p->first, p->second.is_exported, p->second.ext_name, |
| p->second.loc); |
| |
| // Lower calls to builtin functions. |
| ::gogo->lower_builtin_calls(); |
| |
| // Finalize method lists and build stub methods for named types. |
| ::gogo->finalize_methods(); |
| |
| // Check that functions have a terminating statement. |
| ::gogo->check_return_statements(); |
| |
| // At this point we have handled all inline functions, so we no |
| // longer need the linemap. |
| ::gogo->linemap()->stop(); |
| |
| // Work out types of unspecified constants and variables. |
| ::gogo->determine_types(); |
| |
| // Now that we have seen all the names, verify that types are |
| // correct. |
| ::gogo->verify_types(); |
| |
| // Check types and issue errors as appropriate. |
| ::gogo->check_types(); |
| |
| // Now that we have seen all the names and we know all the types, |
| // lower the parse tree into a form which is easier to use. |
| ::gogo->lower_parse_tree(); |
| |
| if (only_check_syntax) |
| return; |
| |
| // Create function descriptors as needed. |
| ::gogo->create_function_descriptors(); |
| |
| // Record global variable initializer dependencies. |
| ::gogo->record_global_init_refs(); |
| |
| // Do simple deadcode elimination. |
| ::gogo->remove_deadcode(); |
| |
| // Make implicit type conversions explicit. |
| ::gogo->add_conversions(); |
| |
| // Analyze the program flow for escape information. |
| ::gogo->analyze_escape(); |
| |
| // Export global identifiers as appropriate. |
| ::gogo->do_exports(); |
| |
| // Use temporary variables to force order of evaluation. |
| ::gogo->order_evaluations(); |
| |
| // Turn short-cut operators (&&, ||) into explicit if statements. |
| ::gogo->remove_shortcuts(); |
| |
| // Convert named types to backend representation. |
| ::gogo->convert_named_types(); |
| |
| // Build thunks for functions which call recover. |
| ::gogo->build_recover_thunks(); |
| |
| // Convert complicated go and defer statements into simpler ones. |
| ::gogo->simplify_thunk_statements(); |
| |
| // Write out queued up functions for hash and comparison of types. |
| ::gogo->write_specific_type_functions(); |
| |
| // Add write barriers. |
| ::gogo->add_write_barriers(); |
| |
| // Flatten the parse tree. |
| ::gogo->flatten(); |
| |
| // Reclaim memory of escape analysis Nodes. |
| ::gogo->reclaim_escape_nodes(); |
| |
| // Dump ast, use filename[0] as the base name |
| ::gogo->dump_ast(filenames[0]); |
| } |
| |
| // Write out globals. |
| |
| GO_EXTERN_C |
| void |
| go_write_globals() |
| { |
| return ::gogo->write_globals(); |
| } |
| |
| // Return the global IR structure. This is used by some of the |
| // langhooks to pass to other code. |
| |
| Gogo* |
| go_get_gogo() |
| { |
| return ::gogo; |
| } |