summaryrefslogtreecommitdiff
path: root/gcc/elna-builtins.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/elna-builtins.cc')
-rw-r--r--gcc/elna-builtins.cc274
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(&parameter_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(&parameter_type));
+ DECL_CONTEXT(declaration_tree) = fndecl;
+ DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(&parameter_type);
+
+ argument_chain = chainon(argument_chain, declaration_tree);
+ function_args_iter_next(&parameter_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);
+ }
+ }
+ }
+}