Implement string comparison

This commit is contained in:
2025-02-12 00:56:21 +01:00
parent 33aca4cc07
commit cd949c4be7
11 changed files with 287 additions and 321 deletions

View File

@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h"
#include "varasm.h"
#include "fold-const.h"
#include "langhooks.h"
#include <set>
namespace elna
@ -69,7 +70,7 @@ namespace gcc
if (return_type == void_type_node)
{
this->scope.front().append_statement(stmt);
append_statement(stmt);
this->current_expression = NULL_TREE;
}
else
@ -96,11 +97,6 @@ namespace gcc
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type));
}
bool generic_visitor::is_numeric_type(tree type)
{
return is_integral_type(type) || type == elna_float_type_node;
}
void generic_visitor::visit(boot::program *program)
{
for (boot::constant_definition *const constant : program->constants)
@ -119,11 +115,8 @@ namespace gcc
{
procedure->accept(this);
}
std::array<tree, 2> parameter_types{
integer_type_node,
build_pointer_type(build_pointer_type(char_type_node))
};
tree declaration_type = build_function_type_array(integer_type_node, 2, parameter_types.data());
tree declaration_type = build_function_type_list(integer_type_node, integer_type_node,
build_pointer_type(build_pointer_type(char_type_node)), NULL_TREE);
tree fndecl = build_fn_decl("main", declaration_type);
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
@ -132,23 +125,21 @@ namespace gcc
push_struct_function(fndecl, false);
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
DECL_STRUCT_FUNCTION(fndecl)->language->binding_level = ggc_cleared_alloc<binding_level>();
enter_scope();
tree_chain argument_chain;
for (std::size_t i = 0; i < 2; ++i)
tree parameter_type = TYPE_ARG_TYPES(declaration_type);
for (const char *argument_name : std::array<const char *, 2>{ "count", "parameters" })
{
std::string argument_name = i == 0 ? "count" : "parameters";
tree argc_declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL,
get_identifier(argument_name.c_str()), parameter_types[i]);
DECL_CONTEXT(argc_declaration_tree) = fndecl;
DECL_ARG_TYPE(argc_declaration_tree) = parameter_types[i];
tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL,
get_identifier(argument_name), TREE_VALUE(parameter_type));
DECL_CONTEXT(declaration_tree) = fndecl;
DECL_ARG_TYPE(declaration_tree) = TREE_VALUE(parameter_type);
argument_chain.append(argc_declaration_tree);
this->symbol_map->enter(argument_name, declaration_tree);
DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree);
parameter_type = TREE_CHAIN(parameter_type);
}
DECL_ARGUMENTS(fndecl) = argument_chain.head();
for (boot::statement *const body_statement : program->body)
{
body_statement->accept(this);
@ -156,12 +147,12 @@ namespace gcc
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(fndecl),
build_int_cst_type(integer_type_node, 0));
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
this->scope.front().append_statement(return_stmt);
tree_symbol_mapping mapping = leave_scope();
append_statement(return_stmt);
tree mapping = leave_scope();
BLOCK_SUPERCONTEXT(mapping.block()) = fndecl;
DECL_INITIAL(fndecl) = mapping.block();
DECL_SAVED_TREE(fndecl) = mapping.bind_expression();
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
DECL_SAVED_TREE(fndecl) = mapping;
DECL_EXTERNAL(fndecl) = 0;
DECL_PRESERVE_P(fndecl) = 1;
@ -189,14 +180,16 @@ namespace gcc
if (definition->body() != nullptr)
{
current_function_decl = fndecl;
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type);
DECL_CONTEXT(resdecl) = fndecl;
DECL_RESULT(fndecl) = resdecl;
push_struct_function(fndecl, false);
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
enter_scope();
}
tree_chain argument_chain;
tree argument_chain = NULL_TREE;
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
{
auto parameter = definition->parameters.at(i);
@ -210,24 +203,24 @@ namespace gcc
{
this->symbol_map->enter(parameter->identifier, declaration_tree);
}
argument_chain.append(declaration_tree);
argument_chain = chainon(argument_chain, declaration_tree);
}
DECL_ARGUMENTS(fndecl) = argument_chain.head();
DECL_ARGUMENTS(fndecl) = argument_chain;
TREE_PUBLIC(fndecl) = definition->exported;
if (definition->body() != nullptr)
{
definition->body()->accept(this);
tree_symbol_mapping mapping = leave_scope();
tree mapping = leave_scope();
BLOCK_SUPERCONTEXT(mapping.block()) = fndecl;
DECL_INITIAL(fndecl) = mapping.block();
DECL_SAVED_TREE(fndecl) = mapping.bind_expression();
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
DECL_SAVED_TREE(fndecl) = mapping;
DECL_EXTERNAL(fndecl) = 0;
DECL_PRESERVE_P(fndecl) = 1;
current_function_decl = NULL_TREE;
pop_cfun();
gimplify_function_tree(fndecl);
cgraph_node::finalize_function(fndecl, true);
}
@ -239,30 +232,35 @@ namespace gcc
void generic_visitor::enter_scope()
{
scope.emplace_front();
this->symbol_map = std::make_shared<boot::symbol_table<tree>>(this->symbol_map);
// Chain the binding levels.
struct binding_level *new_level = ggc_cleared_alloc<binding_level>();
new_level->level_chain = f_binding_level;
new_level->statement_list = alloc_stmt_list();
f_binding_level = new_level;
}
tree_symbol_mapping generic_visitor::leave_scope()
tree generic_visitor::leave_scope()
{
tree new_block = build_block(this->scope.front().variables.head(),
this->scope.front().blocks.head(), NULL_TREE, NULL_TREE);
// Variables are only defined in the top function scope.
tree variables = f_binding_level->level_chain == nullptr ? f_names : NULL_TREE;
tree new_block = build_block(variables, f_binding_level->blocks, NULL_TREE, NULL_TREE);
for (tree it = this->scope.front().blocks.head(); it != NULL_TREE; it = BLOCK_CHAIN(it))
for (tree it = f_binding_level->blocks; it != NULL_TREE; it = BLOCK_CHAIN(it))
{
BLOCK_SUPERCONTEXT(it) = new_block;
}
tree bind_expr = build3(BIND_EXPR, void_type_node, this->scope.front().variables.head(),
this->scope.front().chain_defer(), new_block);
tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block);
this->symbol_map = this->symbol_map->scope();
scope.pop_front();
f_binding_level = f_binding_level->level_chain;
if (!scope.empty())
if (f_binding_level != nullptr)
{
scope.front().blocks.append(new_block);
f_binding_level->blocks = chainon(f_binding_level->blocks, new_block);
}
return tree_symbol_mapping{ bind_expr, new_block };
return bind_expr;
}
tree generic_visitor::lookup(const std::string& name)
@ -295,16 +293,6 @@ namespace gcc
{
return elna_string_type_node;
}
if (current_function_decl != NULL_TREE)
{
for (tree decl = DECL_ARGUMENTS(current_function_decl); decl; decl = DECL_CHAIN(decl))
{
if (name == IDENTIFIER_POINTER(DECL_NAME(decl)))
{
return decl;
}
}
}
return this->symbol_map->lookup(name);
}
@ -392,11 +380,52 @@ namespace gcc
expression, operator_code, left, right, elna_bool_type_node);
}
tree generic_visitor::build_equality_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right)
tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right)
{
return build_binary_operation(true, expression,
operator_code, left, right, elna_bool_type_node);
location_t expression_location = get_location(&expression->position());
tree_code equality_code, combination_code;
if (expression->operation() == boot::binary_operator::equals)
{
equality_code = EQ_EXPR;
combination_code = TRUTH_ANDIF_EXPR;
}
else if (expression->operation() == boot::binary_operator::not_equals)
{
equality_code = NE_EXPR;
combination_code = TRUTH_ORIF_EXPR;
}
else
{
gcc_unreachable();
}
if (TREE_TYPE(left) == elna_string_type_node)
{
tree length_field = TYPE_FIELDS(elna_string_type_node);
tree ptr_field = TREE_CHAIN(length_field);
tree lhs_length = build3(COMPONENT_REF, TREE_TYPE(length_field), left, length_field, NULL_TREE);
tree lhs_ptr = build3(COMPONENT_REF, TREE_TYPE(ptr_field), left, ptr_field, NULL_TREE);
tree rhs_length = build3(COMPONENT_REF, TREE_TYPE(length_field), right, length_field, NULL_TREE);
tree rhs_ptr = build3(COMPONENT_REF, TREE_TYPE(ptr_field), right, ptr_field, NULL_TREE);
tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length);
tree *memcmp = elna_global_decls->get("__builtin_memcmp");
gcc_assert(memcmp != nullptr);
tree fndecl_type = build_function_type(integer_type_node, TYPE_ARG_TYPES(*memcmp));
tree memcmp_addr = build1(ADDR_EXPR, build_pointer_type(fndecl_type), *memcmp);
tree memcmp_call = build_call_nary(integer_type_node, memcmp_addr, 3, lhs_ptr, rhs_ptr, lhs_length);
tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node);
return build2(combination_code, elna_bool_type_node, length_equality, equals_zero);
}
else
{
return build2_loc(expression_location, equality_code, elna_bool_type_node, left, right);
}
}
void generic_visitor::visit(boot::binary_expression *expression)
@ -473,10 +502,10 @@ namespace gcc
this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right);
break;
case boot::binary_operator::equals:
this->current_expression = build_equality_operation(expression, EQ_EXPR, left, right);
this->current_expression = build_equality_operation(expression, left, right);
break;
case boot::binary_operator::not_equals:
this->current_expression = build_equality_operation(expression, NE_EXPR, left, right);
this->current_expression = build_equality_operation(expression, left, right);
break;
}
}
@ -520,11 +549,11 @@ namespace gcc
TREE_READONLY(definition_tree) = 1;
TREE_PUBLIC(definition_tree) = definition->exported;
if (!scope.empty())
if (!lang_hooks.decls.global_bindings_p())
{
auto declaration_statement = build1_loc(definition_location, DECL_EXPR,
void_type_node, definition_tree);
this->scope.front().append_statement(declaration_statement);
append_statement(declaration_statement);
}
}
else
@ -599,7 +628,6 @@ namespace gcc
{
std::set<std::string> field_names;
tree record_type_node = make_node(RECORD_TYPE);
tree_chain record_chain;
for (auto& field : record_type->fields)
{
@ -617,9 +645,8 @@ namespace gcc
}
tree field_declaration = build_field(get_location(&field.second->position()),
record_type_node, field.first, field_type);
record_chain.append(field_declaration);
TYPE_FIELDS(record_type_node) = chainon(TYPE_FIELDS(record_type_node), field_declaration);
}
TYPE_FIELDS(record_type_node) = record_chain.head();
layout_type(record_type_node);
return record_type_node;
@ -628,7 +655,6 @@ namespace gcc
{
std::set<std::string> field_names;
tree union_type_node = make_node(UNION_TYPE);
tree_chain union_chain;
for (auto& field : union_type->fields)
{
@ -646,9 +672,8 @@ namespace gcc
}
tree field_declaration = build_field(get_location(&field.second->position()),
union_type_node, field.first, field_type);
union_chain.append(field_declaration);
TYPE_FIELDS(union_type_node) = chainon(TYPE_FIELDS(union_type_node), field_declaration);
}
TYPE_FIELDS(union_type_node) = union_chain.head();
layout_type(union_type_node);
return union_type_node;
@ -671,7 +696,7 @@ namespace gcc
error_at(declaration_location, "variable '%s' already declared in this scope",
declaration->identifier.c_str());
}
else if (current_function_decl == NULL_TREE)
else if (lang_hooks.decls.global_bindings_p())
{
TREE_STATIC(declaration_tree) = 1;
varpool_node::get_create(declaration_tree);
@ -680,11 +705,11 @@ namespace gcc
else
{
DECL_CONTEXT(declaration_tree) = current_function_decl;
this->scope.front().variables.append(declaration_tree);
f_names = chainon(f_names, declaration_tree);
auto declaration_statement = build1_loc(declaration_location, DECL_EXPR,
void_type_node, declaration_tree);
this->scope.front().append_statement(declaration_statement);
append_statement(declaration_statement);
}
}
@ -779,7 +804,7 @@ namespace gcc
tree assignment = build2_loc(statement_location, MODIFY_EXPR,
void_type_node, lvalue, this->current_expression);
this->scope.front().append_statement(assignment);
append_statement(assignment);
this->current_expression = NULL_TREE;
}
else
@ -810,11 +835,11 @@ namespace gcc
{
body_statement->accept(this);
}
tree_symbol_mapping mapping = leave_scope();
scope.front().append_statement(mapping.bind_expression());
tree mapping = leave_scope();
append_statement(mapping);
}
tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
this->scope.front().append_statement(endif_label_expr);
append_statement(endif_label_expr);
this->current_expression = NULL_TREE;
}
@ -837,22 +862,22 @@ namespace gcc
tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl);
auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else);
this->scope.front().append_statement(cond_expr);
append_statement(cond_expr);
tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl);
this->scope.front().append_statement(then_label_expr);
append_statement(then_label_expr);
enter_scope();
for (const auto body_statement : branch.statements)
{
body_statement->accept(this);
}
tree_symbol_mapping mapping = leave_scope();
this->scope.front().append_statement(mapping.bind_expression());
this->scope.front().append_statement(goto_endif);
tree mapping = leave_scope();
append_statement(mapping);
append_statement(goto_endif);
tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
this->scope.front().append_statement(else_label_expr);
append_statement(else_label_expr);
}
tree generic_visitor::build_label_decl(const char *name, location_t loc)
@ -885,7 +910,7 @@ namespace gcc
auto prerequisite_label_decl = build_label_decl("while_check", prerequisite_location);
auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR,
void_type_node, prerequisite_label_decl);
this->scope.front().append_statement(prerequisite_label_expr);
append_statement(prerequisite_label_expr);
auto body_label_decl = build_label_decl("while_body", body_location);
auto end_label_decl = build_label_decl("end_while", UNKNOWN_LOCATION);
@ -897,24 +922,24 @@ namespace gcc
auto cond_expr = build3_loc(prerequisite_location, COND_EXPR,
void_type_node, this->current_expression, goto_body, goto_end);
this->scope.front().append_statement(cond_expr);
append_statement(cond_expr);
auto body_label_expr = build1_loc(body_location, LABEL_EXPR,
void_type_node, body_label_decl);
this->scope.front().append_statement(body_label_expr);
append_statement(body_label_expr);
for (const auto body_statement : statement->body().statements)
{
body_statement->accept(this);
}
tree_symbol_mapping mapping = leave_scope();
this->scope.front().append_statement(mapping.bind_expression());
tree mapping = leave_scope();
append_statement(mapping);
auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
this->scope.front().append_statement(goto_check);
append_statement(goto_check);
auto endif_label_expr = build1(LABEL_EXPR, void_type_node, end_label_decl);
this->scope.front().append_statement(endif_label_expr);
append_statement(endif_label_expr);
this->current_expression = NULL_TREE;
}
@ -922,7 +947,7 @@ namespace gcc
void generic_visitor::visit(boot::call_statement *statement)
{
statement->body().accept(this);
this->scope.front().append_statement(this->current_expression);
append_statement(this->current_expression);
this->current_expression = NULL_TREE;
}
@ -939,7 +964,7 @@ namespace gcc
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
this->current_expression);
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
this->scope.front().append_statement(return_stmt);
append_statement(return_stmt);
}
void generic_visitor::visit(boot::defer_statement *statement)
@ -949,8 +974,7 @@ namespace gcc
{
body_statement->accept(this);
}
tree_symbol_mapping mapping = leave_scope();
scope.front().defer(mapping.bind_expression());
defer(leave_scope());
}
}
}