diff options
Diffstat (limited to 'gcc/elna-builtins.cc')
| -rw-r--r-- | gcc/elna-builtins.cc | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc new file mode 100644 index 0000000..cf06df8 --- /dev/null +++ b/gcc/elna-builtins.cc @@ -0,0 +1,274 @@ +/* Builtin definitions. + Copyright (C) 2025 Free Software Foundation, Inc. + +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 +<http://www.gnu.org/licenses/>. */ + +#include <algorithm> + +#include "elna/gcc/elna-builtins.h" +#include "elna/gcc/elna1.h" +#include "stor-layout.h" +#include "stringpool.h" +#include "elna/gcc/elna-tree.h" + +namespace elna::gcc +{ + void init_ttree() + { + elna_int_type_node = long_integer_type_node; + elna_word_type_node = size_type_node; + elna_char_type_node = unsigned_char_type_node; + elna_pointer_type_node = ptr_type_node; + elna_float_type_node = double_type_node; + + elna_bool_type_node = boolean_type_node; + elna_bool_true_node = boolean_true_node; + elna_bool_false_node = boolean_false_node; + + elna_pointer_nil_node = null_pointer_node; + + elna_string_type_node = make_node(RECORD_TYPE); + tree string_ptr_type = build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true); + + elna_string_length_field_node = build_field(UNKNOWN_LOCATION, + elna_string_type_node, "length", build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST)); + elna_string_ptr_field_node = build_field(UNKNOWN_LOCATION, + elna_string_type_node, "ptr", build_qualified_type(string_ptr_type, TYPE_QUAL_CONST)); + + TYPE_FIELDS(elna_string_type_node) = chainon(elna_string_ptr_field_node, elna_string_length_field_node); + layout_type(elna_string_type_node); + } + + static + tree declare_builtin_type(std::shared_ptr<symbol_table> symbol_table, const char *name, tree type) + { + tree identifier = get_identifier(name); + tree type_declaration = build_decl(UNKNOWN_LOCATION, TYPE_DECL, identifier, type); + + symbol_table->enter(name, type_declaration); + + return type_declaration; + } + + std::shared_ptr<symbol_table> builtin_symbol_table() + { + std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>(); + + declare_builtin_type(symbol_table, "Int", elna_int_type_node); + declare_builtin_type(symbol_table, "Word", elna_word_type_node); + declare_builtin_type(symbol_table, "Char", elna_char_type_node); + declare_builtin_type(symbol_table, "Bool", elna_bool_type_node); + declare_builtin_type(symbol_table, "Pointer", elna_pointer_type_node); + declare_builtin_type(symbol_table, "Float", elna_float_type_node); + + tree string_declaration = declare_builtin_type(symbol_table, "String", elna_string_type_node); + TYPE_NAME(elna_string_type_node) = DECL_NAME(string_declaration); + TYPE_STUB_DECL(elna_string_type_node) = string_declaration; + + return symbol_table; + } + + tree build_composite_type(const std::vector<frontend::type_field>& fields, tree composite_type_node, + std::shared_ptr<symbol_table> symbols) + { + for (auto& field : fields) + { + tree rewritten_field = get_inner_alias(field.second, symbols); + tree field_declaration = build_field(UNKNOWN_LOCATION, + composite_type_node, field.first, rewritten_field); + TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration); + } + layout_type(composite_type_node); + return composite_type_node; + } + + tree build_procedure_type(const frontend::procedure_type& procedure, std::shared_ptr<symbol_table> symbols) + { + std::vector<tree> parameter_types(procedure.parameters.size()); + + for (std::size_t i = 0; i < procedure.parameters.size(); ++i) + { + parameter_types[i] = get_inner_alias(procedure.parameters.at(i), symbols); + } + tree return_type = void_type_node; + + if (!procedure.return_type.proper_type.empty()) + { + return_type = get_inner_alias(procedure.return_type.proper_type, symbols); + } + return build_function_type_array(return_type, procedure.parameters.size(), parameter_types.data()); + } + + tree get_inner_alias(const frontend::type& type, std::shared_ptr<symbol_table> symbols) + { + if (auto reference = type.get<frontend::primitive_type>()) + { + auto looked_up = symbols->lookup(reference->identifier); + gcc_assert(looked_up != NULL_TREE); + + return TREE_TYPE(looked_up); + } + else if (auto reference = type.get<frontend::record_type>()) + { + tree composite_type_node = make_node(RECORD_TYPE); + + build_composite_type(reference->fields, composite_type_node, symbols); + + return composite_type_node; + } + else if (auto reference = type.get<frontend::union_type>()) + { + tree composite_type_node = make_node(UNION_TYPE); + + build_composite_type(reference->fields, composite_type_node, symbols); + + return composite_type_node; + } + else if (auto reference = type.get<frontend::enumeration_type>()) + { + return build_enumeration_type(reference->members); + } + else if (auto reference = type.get<frontend::pointer_type>()) + { + return build_global_pointer_type(get_inner_alias(reference->base, symbols)); + } + else if (auto reference = type.get<frontend::array_type>()) + { + tree base = get_inner_alias(reference->base, symbols); + + return build_static_array_type(base, reference->size); + } + else if (auto reference = type.get<frontend::procedure_type>()) + { + auto procedure = build_procedure_type(*reference, symbols); + + return build_global_pointer_type(procedure); + } + else if (auto reference = type.get<frontend::alias_type>()) + { + return TREE_TYPE(handle_symbol(reference->name, reference, symbols)); + } + return error_mark_node; + } + + tree handle_symbol(const std::string& symbol_name, std::shared_ptr<frontend::alias_type> reference, + std::shared_ptr<symbol_table> symbols) + { + tree looked_up = symbols->lookup(symbol_name); + + if (looked_up == NULL_TREE) + { + tree type_tree = get_inner_alias(reference->reference, symbols); + looked_up = build_decl(UNKNOWN_LOCATION, TYPE_DECL, + get_identifier(symbol_name.c_str()), type_tree); + + TREE_PUBLIC(looked_up) = 1; + if (is_unique_type(type_tree)) + { + TYPE_NAME(type_tree) = DECL_NAME(looked_up); + TYPE_STUB_DECL(type_tree) = looked_up; + } + else + { + TYPE_NAME(type_tree) = looked_up; + } + symbols->enter(symbol_name, looked_up); + } + return looked_up; + } + + void declare_procedure(const std::string& name, const frontend::procedure_info& info, + std::shared_ptr<symbol_table> symbols) + { + tree declaration_type = gcc::build_procedure_type(info.symbol, symbols); + tree fndecl = build_fn_decl(name.c_str(), declaration_type); + symbols->enter(name, fndecl); + + if (info.symbol.return_type.no_return) + { + TREE_THIS_VOLATILE(fndecl) = 1; + } + tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type)); + DECL_CONTEXT(resdecl) = fndecl; + DECL_RESULT(fndecl) = resdecl; + + tree argument_chain = NULL_TREE; + function_args_iterator parameter_type; + function_args_iter_init(¶meter_type, declaration_type); + + std::vector<std::string>::const_iterator parameter_name = info.names.cbegin(); + + for (frontend::type parameter : info.symbol.parameters) + { + tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL, + get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type)); + DECL_CONTEXT(declaration_tree) = fndecl; + DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type); + + argument_chain = chainon(argument_chain, declaration_tree); + function_args_iter_next(¶meter_type); + ++parameter_name; + } + DECL_ARGUMENTS(fndecl) = argument_chain; + TREE_ADDRESSABLE(fndecl) = 1; + DECL_EXTERNAL(fndecl) = info.is_extern(); + TREE_PUBLIC(fndecl) = info.exported; + } + + tree declare_variable(const std::string& name, const frontend::variable_info& info, + std::shared_ptr<symbol_table> symbols) + { + auto variable_type = get_inner_alias(info.symbol, symbols); + tree declaration_tree = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(name.c_str()), variable_type); + + TREE_ADDRESSABLE(declaration_tree) = 1; + DECL_EXTERNAL(declaration_tree) = info.is_extern; + TREE_PUBLIC(declaration_tree) = info.exported; + + symbols->enter(name, declaration_tree); + + return declaration_tree; + } + + void declare_type(const std::string& name, const frontend::type_info& info, std::shared_ptr<symbol_table> symbols) + { + // The top level symbol table has basic (builtin) types in it which are not aliases. + if (auto alias_type = info.symbol.get<frontend::alias_type>()) + { + tree type_declaration = handle_symbol(name, alias_type, symbols); + + TREE_PUBLIC(type_declaration) = info.exported; + } + } + + void rewrite_symbol_table(std::shared_ptr<frontend::symbol_table> info_table, std::shared_ptr<symbol_table> symbols) + { + for (auto& [symbol_name, symbol_info] : *info_table) + { + if (auto type_info = symbol_info->is_type()) + { + declare_type(symbol_name, *type_info, symbols); + } + else if (auto variable_info = symbol_info->is_variable()) + { + declare_variable(symbol_name, *variable_info, symbols); + } + else if (auto procedure_info = symbol_info->is_procedure()) + { + declare_procedure(symbol_name, *procedure_info, symbols); + } + } + } +} |
