/* 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 . */ #include "elna/gcc/elna-tree.h" #include "elna/gcc/elna-diagnostic.h" #include "stor-layout.h" #include "fold-const.h" #include "diagnostic-core.h" #include "stringpool.h" namespace elna { namespace gcc { bool is_pointer_type(tree type) { gcc_assert(TYPE_P(type)); return TREE_CODE(type) == POINTER_TYPE; } bool is_integral_type(tree type) { gcc_assert(TYPE_P(type)); return TREE_CODE(type) == INTEGER_TYPE; } bool are_compatible_pointers(tree lhs, tree rhs) { tree lhs_type = TREE_TYPE(lhs); tree rhs_type = TREE_TYPE(rhs); return (is_pointer_type(lhs_type) && rhs == null_pointer_node) || (is_pointer_type(lhs_type) && lhs_type == rhs_type); } tree tree_chain_base::head() { return first; } void tree_chain_base::append(tree t) { gcc_assert(t != NULL_TREE); if (this->first == NULL_TREE) { this->first = this->last = t; } else { chain(t); this->last = t; } } void tree_chain::chain(tree t) { TREE_CHAIN(this->last) = t; } void block_chain::chain(tree t) { BLOCK_CHAIN(this->last) = t; } tree_symbol_mapping::tree_symbol_mapping(tree bind_expression, tree block) : m_bind_expression(bind_expression), m_block(block) { } tree tree_symbol_mapping::bind_expression() { return m_bind_expression; } tree tree_symbol_mapping::block() { return m_block; } block_scope::block_scope() : m_statement_list(alloc_stmt_list()) { } void block_scope::append_statement(tree statement_tree) { if (!defers.empty()) { append_to_statement_list(statement_tree, &this->defers.front().second); } else { append_to_statement_list(statement_tree, &this->m_statement_list); } } void block_scope::defer(tree statement_tree) { defers.push_front({ statement_tree, alloc_stmt_list() }); } tree block_scope::chain_defer() { if (this->defers.empty()) { return m_statement_list; } std::forward_list>::iterator defer_iterator = this->defers.begin(); tree defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, defer_iterator->second, defer_iterator->first); ++defer_iterator; for (; defer_iterator != this->defers.end(); ++defer_iterator) { append_to_statement_list(defer_tree, &defer_iterator->second); defer_tree = build2(TRY_FINALLY_EXPR, void_type_node, defer_iterator->second, defer_iterator->first); } return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), m_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; } std::shared_ptr> builtin_symbol_table() { std::shared_ptr> initial_table = std::make_shared>(); initial_table->enter("Int", long_integer_type_node); initial_table->enter("Word", size_type_node); initial_table->enter("Bool", boolean_type_node); initial_table->enter("Float", double_type_node); initial_table->enter("Char", unsigned_char_type_node); initial_table->enter("Byte", make_unsigned_type(8)); tree string_record = make_node(RECORD_TYPE); tree_chain record_chain; record_chain.append(build_field(UNKNOWN_LOCATION, string_record, "length", initial_table->lookup("Word"))); record_chain.append(build_field(UNKNOWN_LOCATION, string_record, "ptr", build_pointer_type_for_mode(initial_table->lookup("Char"), VOIDmode, true))); TYPE_FIELDS(string_record) = record_chain.head(); layout_type(string_record); initial_table->enter("String", string_record); return initial_table; } tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right) { if (binary_operator == boot::binary_operator::sum) { tree pointer{ NULL_TREE }; tree offset{ NULL_TREE }; if (is_pointer_type(TREE_TYPE(left)) && is_integral_type(TREE_TYPE(right))) { pointer = left; offset = right; } else if (is_integral_type(TREE_TYPE(left)) && is_pointer_type(TREE_TYPE(right))) { pointer = right; offset = left; } else { return error_mark_node; } tree size_exp = 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(POINTER_PLUS_EXPR, TREE_TYPE(pointer), pointer, offset); } else if (binary_operator == boot::binary_operator::subtraction) { if (is_pointer_type(TREE_TYPE(left)) && is_integral_type(TREE_TYPE(right))) { tree pointer_type = TREE_TYPE(left); tree offset_type = TREE_TYPE(right); 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(POINTER_PLUS_EXPR, pointer_type, left, convert_expression); } else if (is_pointer_type(TREE_TYPE(left)) && is_pointer_type(TREE_TYPE(right)) && TREE_TYPE(left) == TREE_TYPE(right)) { return fold_build2(POINTER_DIFF_EXPR, ssizetype, left, right); } } return error_mark_node; } tree build_binary_operation(bool condition, boot::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 = TREE_TYPE(left); tree right_type = TREE_TYPE(right); if (condition) { return 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::boot::print_binary_operator(expression->operation())); return error_mark_node; } } } }