diff options
| author | Eugen Wissner <belka@caraus.de> | 2025-12-02 10:22:06 +0100 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2025-12-02 17:14:18 +0100 |
| commit | 23b6f074c7f560d701e9a1fa5713a965af3a18a3 (patch) | |
| tree | 87549a4eba3da8d8ed6e3fbb2e337e152a8bc96a /gcc/elna-tree.cc | |
| parent | 5f7d83974114c73327ce9fff3635927df050b5e4 (diff) | |
| download | elna-23b6f074c7f560d701e9a1fa5713a965af3a18a3.tar.gz | |
Merge GCC frontend into the branch
Diffstat (limited to 'gcc/elna-tree.cc')
| -rw-r--r-- | gcc/elna-tree.cc | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc new file mode 100644 index 0000000..93f796b --- /dev/null +++ b/gcc/elna-tree.cc @@ -0,0 +1,315 @@ +/* Utilities to manipulate GCC trees. + 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 "elna/gcc/elna-tree.h" +#include "elna/gcc/elna-diagnostic.h" +#include "elna/gcc/elna1.h" + +#include "function.h" +#include "stor-layout.h" +#include "diagnostic-core.h" + +namespace elna::gcc +{ + bool is_integral_type(tree type) + { + gcc_assert(TYPE_P(type)); + return TREE_CODE(type) == INTEGER_TYPE && type != elna_char_type_node; + } + + bool is_numeric_type(tree type) + { + return is_integral_type(type) || type == elna_float_type_node; + } + + bool is_unique_type(tree type) + { + gcc_assert(TYPE_P(type)); + return RECORD_OR_UNION_TYPE_P(type) || TREE_CODE(type) == ENUMERAL_TYPE; + } + + bool is_void_type(tree type) + { + return type == NULL_TREE || type == void_type_node; + } + + bool is_castable_type(tree type) + { + gcc_assert(TYPE_P(type)); + return INTEGRAL_TYPE_P(type) || POINTER_TYPE_P(type) || TREE_CODE(type) == REAL_TYPE; + } + + bool are_compatible_pointers(tree lhs_type, tree rhs) + { + gcc_assert(TYPE_P(lhs_type)); + tree rhs_type = TREE_TYPE(rhs); + + return (POINTER_TYPE_P(lhs_type) && rhs == elna_pointer_nil_node) + || (POINTER_TYPE_P(lhs_type) && lhs_type == rhs_type); + } + + tree prepare_rvalue(tree rvalue) + { + if (DECL_P(rvalue) && TREE_CODE(TREE_TYPE(rvalue)) == FUNCTION_TYPE) + { + return build1(ADDR_EXPR, build_pointer_type_for_mode(TREE_TYPE(rvalue), VOIDmode, true), rvalue); + } + else + { + return rvalue; + } + } + + bool is_assignable_from(tree assignee, tree assignment) + { + return get_qualified_type(TREE_TYPE(assignment), TYPE_UNQUALIFIED) == assignee + || are_compatible_pointers(assignee, assignment); + } + + void append_statement(tree statement_tree) + { + if (!vec_safe_is_empty(f_binding_level->defers)) + { + append_to_statement_list(statement_tree, &f_binding_level->defers->begin()->try_statements); + } + else + { + append_to_statement_list(statement_tree, &f_binding_level->statement_list); + } + } + + void defer(tree statement_tree) + { + defer_scope new_defer{ statement_tree, alloc_stmt_list() }; + vec_safe_insert(f_binding_level->defers, 0, new_defer); + } + + tree chain_defer() + { + if (vec_safe_is_empty(f_binding_level->defers)) + { + return f_binding_level->statement_list; + } + defer_scope *defer_iterator = f_binding_level->defers->begin(); + tree defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, + defer_iterator->try_statements, defer_iterator->defer_block); + int i; + + FOR_EACH_VEC_ELT_FROM(*f_binding_level->defers, i, defer_iterator, 1) + { + append_to_statement_list(defer_tree, &defer_iterator->try_statements); + defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, + defer_iterator->try_statements, defer_iterator->defer_block); + } + return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), f_binding_level->statement_list, defer_tree); + } + + tree build_field(location_t location, tree record_type, const std::string name, tree type) + { + tree field_declaration = build_decl(location, + FIELD_DECL, get_identifier(name.c_str()), type); + TREE_ADDRESSABLE(field_declaration) = 1; + DECL_CONTEXT(field_declaration) = record_type; + + return field_declaration; + } + + tree do_pointer_arithmetic(frontend::binary_operator binary_operator, + tree left, tree right, location_t operation_location) + { + tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED); + tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED); + if (binary_operator == frontend::binary_operator::sum) + { + tree pointer{ NULL_TREE }; + tree offset{ NULL_TREE }; + tree pointer_type{ NULL_TREE }; + + if (POINTER_TYPE_P(left_type) && is_integral_type(right_type)) + { + pointer = left; + offset = right; + pointer_type = left_type; + } + else if (is_integral_type(left_type) && POINTER_TYPE_P(right_type)) + { + pointer = right; + offset = left; + pointer_type = right_type; + } + else + { + return error_mark_node; + } + tree size_exp = pointer_type == elna_pointer_type_node + ? size_one_node + : fold_convert(TREE_TYPE(offset), size_in_bytes(TREE_TYPE(TREE_TYPE(pointer)))); + + offset = fold_build2(MULT_EXPR, TREE_TYPE(offset), offset, size_exp); + offset = fold_convert(sizetype, offset); + + return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, TREE_TYPE(pointer), pointer, offset); + } + else if (binary_operator == frontend::binary_operator::subtraction) + { + if (POINTER_TYPE_P(left_type) && is_integral_type(right_type)) + { + tree pointer_type = left_type; + tree offset_type = right_type; + tree size_exp = fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type))); + + tree convert_expression = fold_build2(MULT_EXPR, offset_type, right, size_exp); + convert_expression = fold_convert(sizetype, convert_expression); + + convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression); + return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, pointer_type, left, convert_expression); + } + else if (POINTER_TYPE_P(left_type) && POINTER_TYPE_P(right_type) && left_type == right_type) + { + return fold_build2_loc(operation_location, POINTER_DIFF_EXPR, ssizetype, left, right); + } + } + gcc_unreachable(); + } + + tree build_binary_operation(bool condition, frontend::binary_expression *expression, + tree_code operator_code, tree left, tree right, tree target_type) + { + location_t expression_location = get_location(&expression->position()); + tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED); + tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED); + + if (condition) + { + return fold_build2_loc(expression_location, operator_code, target_type, left, right); + } + else + { + error_at(expression_location, + "invalid operands of type '%s' and '%s' for operator %s", + print_type(left_type).c_str(), print_type(right_type).c_str(), + elna::frontend::print_binary_operator(expression->operation())); + return error_mark_node; + } + } + + tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name) + { + if (type == error_mark_node) + { + return type; + } + tree field_declaration = TYPE_FIELDS(type); + + if (!RECORD_OR_UNION_TYPE_P(type)) + { + error_at(expression_location, "Type '%s' does not have a field named '%s'", + print_type(type).c_str(), field_name.c_str()); + return error_mark_node; + } + while (field_declaration != NULL_TREE) + { + tree declaration_name = DECL_NAME(field_declaration); + const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name); + + if (field_name == identifier_pointer) + { + break; + } + field_declaration = TREE_CHAIN(field_declaration); + } + if (field_declaration == NULL_TREE) + { + error_at(expression_location, "Aggregate type does not have a field '%s'", field_name.c_str()); + return error_mark_node; + } + return field_declaration; + } + + tree build_global_pointer_type(tree type) + { + return build_pointer_type_for_mode(type, VOIDmode, true); + } + + tree build_static_array_type(tree type, const std::uint64_t size) + { + tree upper_bound = build_int_cst_type(integer_type_node, size); + tree range_type = build_range_type(integer_type_node, size_one_node, upper_bound); + + return build_array_type(type, range_type); + } + + tree build_enumeration_type(const std::vector<std::string>& members) + { + tree composite_type_node = make_node(ENUMERAL_TYPE); + const tree base_type = integer_type_node; + + TREE_TYPE(composite_type_node) = base_type; + ENUM_IS_SCOPED(composite_type_node) = 1; + + tree *pp = &TYPE_VALUES(composite_type_node); + std::size_t order{ 1 }; + + for (const std::string& member : members) + { + tree member_name = get_identifier(member.c_str()); + tree member_declaration = build_decl(UNKNOWN_LOCATION, CONST_DECL, member_name, composite_type_node); + + DECL_CONTEXT(member_declaration) = composite_type_node; + DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++); + TREE_CONSTANT(member_declaration) = 1; + TREE_READONLY(member_declaration) = 1; + + TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration); + + *pp = build_tree_list(member_name, member_declaration); + pp = &TREE_CHAIN(*pp); + } + TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node))); + TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type); + SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type)); + TYPE_SIZE(composite_type_node) = NULL_TREE; + TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type); + + layout_type(composite_type_node); + return composite_type_node; + } + + tree build_label_decl(const char *name, location_t loc) + { + auto label_decl = build_decl(loc, LABEL_DECL, get_identifier(name), void_type_node); + + DECL_CONTEXT(label_decl) = current_function_decl; + + return label_decl; + } + + tree extract_constant(tree expression) + { + int code = TREE_CODE(expression); + + if (code == CONST_DECL) + { + return DECL_INITIAL(expression); + } + else if (TREE_CODE_CLASS(code) == tcc_constant) + { + return expression; + } + return NULL_TREE; + } +} |
