/* 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 "elna/gcc/elna1.h" #include "function.h" #include "stor-layout.h" #include "fold-const.h" #include "diagnostic-core.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 is_numeric_type(tree type) { return is_integral_type(type) || type == elna_float_type_node; } bool is_array_type(tree type) { gcc_assert(TYPE_P(type)); return TREE_CODE(type) == ARRAY_TYPE; } bool is_procedure_type(tree type) { gcc_assert(TYPE_P(type)); return TREE_CODE(type) == FUNCTION_TYPE; } bool is_void_type(tree type) { return type == NULL_TREE || type == void_type_node; } 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 == elna_pointer_nil_node) || (is_pointer_type(lhs_type) && lhs_type == rhs_type); } 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(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); } } gcc_unreachable(); } 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; } } } }