Merge GCC frontend into the branch
This commit is contained in:
315
gcc/elna-tree.cc
Normal file
315
gcc/elna-tree.cc
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user