From 275fa4bff6d153019b6914fed7127a7d919ca177 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Thu, 23 Jul 2026 01:01:03 +0200 Subject: Implement for loop --- gcc/gcc/elna-builtins.cc | 2 +- gcc/gcc/elna-generic.cc | 103 +++++++++++++++++++++++++++++++++++++---------- gcc/gcc/elna-tree.cc | 9 ----- 3 files changed, 82 insertions(+), 32 deletions(-) (limited to 'gcc') diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index 77ffb1c..2790251 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -237,7 +237,7 @@ namespace elna::gcc tree declare_variable(const std::string& name, const boot::variable_info& info, std::shared_ptr symbols) { - auto variable_type = get_inner_alias(info.symbol, symbols); + auto *variable_type = get_inner_alias(info.symbol, symbols); tree declaration_tree = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(name.c_str()), variable_type); TREE_ADDRESSABLE(declaration_tree) = 1; diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index c2c59aa..6fe3da9 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -228,7 +228,7 @@ namespace elna::gcc if (TREE_CODE(base_type) == ARRAY_TYPE) { // Elna arrays are 1-indexed in TYPE_DOMAIN. Pass the raw - // (1-based) start index — GCC handles the 1→0 conversion + // (1-based) start index since GCC handles the 1→0 conversion // via the domain lower bound. No -1 adjustment needed here. slice_ptr = build4_loc(location, ARRAY_REF, TREE_TYPE(base_type), base, start_index, size_one_node, NULL_TREE); @@ -256,10 +256,6 @@ namespace elna::gcc void generic_visitor::visit(boot::unit *unit) { - for (boot::import_declaration *const declaration : unit->imports) - { - declaration->accept(this); - } for (boot::variable_declaration *const variable : unit->variables) { variable->accept(this); @@ -363,15 +359,13 @@ namespace elna::gcc tree generic_visitor::leave_scope() { - // 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); + tree new_block = build_block(f_binding_level->names, f_binding_level->blocks, NULL_TREE, NULL_TREE); 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, variables, chain_defer(), new_block); + tree bind_expr = build3(BIND_EXPR, void_type_node, f_binding_level->names, chain_defer(), new_block); this->symbols = this->symbols->scope(); f_binding_level = f_binding_level->level_chain; @@ -639,27 +633,27 @@ namespace elna::gcc case exclusive_disjunction: gcc_unreachable(); case logical_conjunction: - this->current_expression = build2_loc(expression_location, + this->current_expression = fold_build2_loc(expression_location, TRUTH_ANDIF_EXPR, elna_bool_type_node, left, right); break; case logical_disjunction: - this->current_expression = build2_loc(expression_location, + this->current_expression = fold_build2_loc(expression_location, TRUTH_ORIF_EXPR, elna_bool_type_node, left, right); break; case logical_exclusive_disjunction: - this->current_expression = build2_loc(expression_location, + this->current_expression = fold_build2_loc(expression_location, TRUTH_XOR_EXPR, elna_bool_type_node, left, right); break; case bitwise_conjunction: - this->current_expression = build2_loc(expression_location, + this->current_expression = fold_build2_loc(expression_location, BIT_AND_EXPR, left_type, left, right); break; case bitwise_disjunction: - this->current_expression = build2_loc(expression_location, + this->current_expression = fold_build2_loc(expression_location, BIT_IOR_EXPR, left_type, left, right); break; case bitwise_exclusive_disjunction: - this->current_expression = build2_loc(expression_location, + this->current_expression = fold_build2_loc(expression_location, BIT_XOR_EXPR, left_type, left, right); break; case equals: @@ -780,7 +774,7 @@ namespace elna::gcc else { DECL_CONTEXT(declaration_tree) = current_function_decl; - f_names = chainon(f_names, declaration_tree); + f_binding_level->names = chainon(f_binding_level->names, declaration_tree); auto *declaration_statement = build1_loc(declaration_location, DECL_EXPR, void_type_node, declaration_tree); @@ -1031,7 +1025,7 @@ namespace elna::gcc } else { - tree assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, rvalue); + tree assignment = fold_build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, rvalue); append_statement(assignment); } @@ -1088,21 +1082,86 @@ namespace elna::gcc return build3(COND_EXPR, void_type_node, condition, then_body, next); } - void generic_visitor::visit(boot::import_declaration *) + void generic_visitor::visit(boot::for_statement *statement) { + statement->initial_value().accept(this); + tree initial_value = this->current_expression; + + statement->final_value().accept(this); + tree final_value = this->current_expression; + + tree step; + location_t step_location = UNKNOWN_LOCATION; + if (statement->step != nullptr) + { + statement->step->accept(this); + step = this->current_expression; + step_location = get_location(&statement->step->position()); + } + enter_scope(); + // Declare control variable with the unqualified type. The constant_type wrapper + // is for semantic checking only, because GENERIC needs to modify the control variable. + auto control_variable_info = statement->symbols->lookup(statement->control_variable.name()); + boot::variable_info unqualified_info(resolve_underlying_type(control_variable_info->is_variable()->symbol), + control_variable_info->is_variable()->is_extern); + tree control_variable_declaration = declare_variable(statement->control_variable.name(), + unqualified_info, this->symbols); + DECL_CONTEXT(control_variable_declaration) = current_function_decl; + f_binding_level->names = chainon(f_binding_level->names, control_variable_declaration); + DECL_INITIAL(control_variable_declaration) = initial_value; + tree declaration_statement = build1_loc(get_location(&statement->control_variable.position()), + DECL_EXPR, void_type_node, control_variable_declaration); + append_statement(declaration_statement); + + tree control_type = TREE_TYPE(control_variable_declaration); + if (statement->step == nullptr) + { + step = build_int_cst_type(control_type, 1); + } + + // Put a label in front of the loop condition. + location_t check_location = get_location(&statement->position()); + tree check_label = create_artificial_label(check_location); + tree check_statement = build1_loc(check_location, LABEL_EXPR, void_type_node, check_label); + append_statement(check_statement); + + // Build the condition and jump if the condition isn't met. + tree condition = fold_build2(LE_EXPR, elna_bool_type_node, control_variable_declaration, final_value); + tree end_label = create_artificial_label(UNKNOWN_LOCATION); + tree goto_end = build1(GOTO_EXPR, void_type_node, end_label); + tree condition_statement = build3_loc(check_location, COND_EXPR, void_type_node, + condition, NULL_TREE, goto_end); + append_statement(condition_statement); + + for (auto *body_statement : statement->body) + { + body_statement->accept(this); + } + // Adjust the control variable by step and jump to check the condition. + tree step_expression = fold_build2_loc(step_location, PLUS_EXPR, control_type, + control_variable_declaration, step); + append_statement(build2(MODIFY_EXPR, void_type_node, control_variable_declaration, step_expression)); + tree goto_check = build1(GOTO_EXPR, void_type_node, check_label); + append_statement(goto_check); + tree end_statement = build1(LABEL_EXPR, void_type_node, end_label); + append_statement(end_statement); + + tree for_binding = leave_scope(); + append_statement(for_binding); + + this->current_expression = NULL_TREE; } void generic_visitor::visit(boot::while_statement *statement) { location_t prerequisite_location = get_location(&statement->branch().prerequisite().position()); - tree while_check_label = build_label_decl("while_do", prerequisite_location); - tree while_end_label = build_label_decl("while_end", UNKNOWN_LOCATION); + tree while_check_label = create_artificial_label(prerequisite_location); + tree while_end_label = create_artificial_label(UNKNOWN_LOCATION); tree goto_check = build1(GOTO_EXPR, void_type_node, while_check_label); tree result = NULL_TREE; - auto& branches = statement->branches; - for (auto& branch : branches | std::views::reverse) + for (boot::conditional_statements *branch : statement->branches | std::views::reverse) { result = make_if_branch(*branch, result, goto_check); } diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index ab7363f..2568430 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -249,15 +249,6 @@ namespace elna::gcc 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); -- cgit v1.2.3