2025-02-09 12:30:31 +01:00
|
|
|
/* Utilities to manipulate GCC trees.
|
2025-02-08 23:02:27 +01:00
|
|
|
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/>. */
|
|
|
|
|
2024-12-29 22:28:53 +01:00
|
|
|
#include "elna/gcc/elna-tree.h"
|
2025-02-02 08:22:40 +01:00
|
|
|
#include "elna/gcc/elna-diagnostic.h"
|
2025-02-11 01:37:55 +01:00
|
|
|
#include "elna/gcc/elna1.h"
|
2024-12-29 22:28:53 +01:00
|
|
|
|
2025-02-12 00:56:21 +01:00
|
|
|
#include "function.h"
|
2025-01-01 23:02:19 +01:00
|
|
|
#include "stor-layout.h"
|
2025-02-02 08:22:40 +01:00
|
|
|
#include "fold-const.h"
|
|
|
|
#include "diagnostic-core.h"
|
2025-01-01 23:02:19 +01:00
|
|
|
|
2025-01-03 22:18:35 +01:00
|
|
|
namespace elna
|
2025-01-01 23:02:19 +01:00
|
|
|
{
|
2025-01-03 22:18:35 +01:00
|
|
|
namespace gcc
|
|
|
|
{
|
2025-01-10 23:17:18 +01:00
|
|
|
bool is_pointer_type(tree type)
|
2025-01-03 22:18:35 +01:00
|
|
|
{
|
|
|
|
gcc_assert(TYPE_P(type));
|
2025-01-10 23:17:18 +01:00
|
|
|
return TREE_CODE(type) == POINTER_TYPE;
|
|
|
|
}
|
|
|
|
|
2025-02-05 13:24:50 +01:00
|
|
|
bool is_integral_type(tree type)
|
|
|
|
{
|
|
|
|
gcc_assert(TYPE_P(type));
|
|
|
|
return TREE_CODE(type) == INTEGER_TYPE;
|
|
|
|
}
|
|
|
|
|
2025-02-12 00:56:21 +01:00
|
|
|
bool is_numeric_type(tree type)
|
|
|
|
{
|
|
|
|
return is_integral_type(type) || type == elna_float_type_node;
|
|
|
|
}
|
|
|
|
|
2025-02-12 20:47:47 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-02-14 08:05:03 +01:00
|
|
|
bool is_aggregate_type(tree type)
|
2025-02-13 22:54:47 +01:00
|
|
|
{
|
2025-02-14 08:05:03 +01:00
|
|
|
gcc_assert(TYPE_P(type));
|
|
|
|
return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE;
|
2025-02-13 22:54:47 +01:00
|
|
|
}
|
|
|
|
|
2025-02-14 08:05:03 +01:00
|
|
|
bool are_compatible_pointers(tree lhs_type, tree rhs)
|
2025-02-03 23:04:00 +01:00
|
|
|
{
|
2025-02-14 08:05:03 +01:00
|
|
|
gcc_assert(TYPE_P(lhs_type));
|
2025-02-08 23:02:27 +01:00
|
|
|
tree rhs_type = TREE_TYPE(rhs);
|
|
|
|
|
2025-02-12 13:32:59 +01:00
|
|
|
return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node)
|
2025-02-08 23:02:27 +01:00
|
|
|
|| (is_pointer_type(lhs_type) && lhs_type == rhs_type);
|
2025-02-03 23:04:00 +01:00
|
|
|
}
|
|
|
|
|
2025-02-14 08:05:03 +01:00
|
|
|
bool is_assignable_from(tree assignee, tree assignment)
|
|
|
|
{
|
2025-02-15 10:26:04 +01:00
|
|
|
return get_qualified_type(TREE_TYPE(assignment), TYPE_UNQUALIFIED) == assignee
|
2025-02-14 08:05:03 +01:00
|
|
|
|| are_compatible_pointers(assignee, assignment);
|
|
|
|
}
|
|
|
|
|
2025-02-12 00:56:21 +01:00
|
|
|
void append_statement(tree statement_tree)
|
2025-02-07 22:12:59 +01:00
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
if (!vec_safe_is_empty(f_binding_level->defers))
|
2025-02-07 22:12:59 +01:00
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
append_to_statement_list(statement_tree, &f_binding_level->defers->begin()->try_statements);
|
2025-02-07 22:12:59 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
append_to_statement_list(statement_tree, &f_binding_level->statement_list);
|
2025-02-07 22:12:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-12 00:56:21 +01:00
|
|
|
void defer(tree statement_tree)
|
2025-02-07 22:12:59 +01:00
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
defer_scope new_defer{ statement_tree, alloc_stmt_list() };
|
|
|
|
vec_safe_insert(f_binding_level->defers, 0, new_defer);
|
2025-02-07 22:12:59 +01:00
|
|
|
}
|
|
|
|
|
2025-02-12 00:56:21 +01:00
|
|
|
tree chain_defer()
|
2025-02-07 22:12:59 +01:00
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
if (vec_safe_is_empty(f_binding_level->defers))
|
2025-02-07 22:12:59 +01:00
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
return f_binding_level->statement_list;
|
2025-02-07 22:12:59 +01:00
|
|
|
}
|
2025-02-12 00:56:21 +01:00
|
|
|
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;
|
2025-02-07 22:12:59 +01:00
|
|
|
|
2025-02-12 00:56:21 +01:00
|
|
|
FOR_EACH_VEC_ELT_FROM(*f_binding_level->defers, i, defer_iterator, 1)
|
2025-02-07 22:12:59 +01:00
|
|
|
{
|
2025-02-12 00:56:21 +01:00
|
|
|
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);
|
2025-02-07 22:12:59 +01:00
|
|
|
}
|
2025-02-12 00:56:21 +01:00
|
|
|
return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), f_binding_level->statement_list, defer_tree);
|
2025-02-07 22:12:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-02-02 08:22:40 +01:00
|
|
|
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right)
|
|
|
|
{
|
2025-02-15 10:26:04 +01:00
|
|
|
tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
|
|
|
|
tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
|
2025-02-02 08:22:40 +01:00
|
|
|
if (binary_operator == boot::binary_operator::sum)
|
|
|
|
{
|
2025-02-05 13:24:50 +01:00
|
|
|
tree pointer{ NULL_TREE };
|
|
|
|
tree offset{ NULL_TREE };
|
|
|
|
|
2025-02-15 10:26:04 +01:00
|
|
|
if (is_pointer_type(left_type) && is_integral_type(right_type))
|
2025-02-05 13:24:50 +01:00
|
|
|
{
|
|
|
|
pointer = left;
|
|
|
|
offset = right;
|
|
|
|
}
|
2025-02-15 10:26:04 +01:00
|
|
|
else if (is_integral_type(left_type) && is_pointer_type(right_type))
|
2025-02-05 13:24:50 +01:00
|
|
|
{
|
|
|
|
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);
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
|
|
|
else if (binary_operator == boot::binary_operator::subtraction)
|
|
|
|
{
|
2025-02-15 10:26:04 +01:00
|
|
|
if (is_pointer_type(left_type) && is_integral_type(right_type))
|
2025-02-05 13:24:50 +01:00
|
|
|
{
|
2025-02-15 10:26:04 +01:00
|
|
|
tree pointer_type = left_type;
|
|
|
|
tree offset_type = right_type;
|
2025-02-05 13:24:50 +01:00
|
|
|
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);
|
2025-02-15 10:26:04 +01:00
|
|
|
}
|
|
|
|
else if (is_pointer_type(left_type) && is_pointer_type(right_type) && left_type == right_type)
|
2025-02-05 13:24:50 +01:00
|
|
|
{
|
|
|
|
return fold_build2(POINTER_DIFF_EXPR, ssizetype, left, right);
|
|
|
|
}
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
2025-02-12 20:47:47 +01:00
|
|
|
gcc_unreachable();
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
2025-02-15 10:26:04 +01:00
|
|
|
tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
|
|
|
|
tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
|
2025-02-02 08:22:40 +01:00
|
|
|
|
|
|
|
if (condition)
|
|
|
|
{
|
|
|
|
return build2_loc(expression_location, operator_code, target_type, left, right);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error_at(expression_location,
|
2025-02-15 00:38:46 +01:00
|
|
|
"invalid operands of type '%s' and '%s' for operator %s",
|
2025-02-08 23:02:27 +01:00
|
|
|
print_type(left_type).c_str(), print_type(right_type).c_str(),
|
2025-02-02 08:22:40 +01:00
|
|
|
elna::boot::print_binary_operator(expression->operation()));
|
|
|
|
return error_mark_node;
|
|
|
|
}
|
|
|
|
}
|
2025-01-03 22:18:35 +01:00
|
|
|
}
|
2025-01-01 23:02:19 +01:00
|
|
|
}
|